/*if it is a SW VLAN check the next protocol*/ if (protocol == htons(ETH_P_8021Q)) {
ip_offset += VLAN_HLEN;
protocol = vlan_get_protocol(skb);
skb->protocol = protocol;
}
staticvoid fill_tso_desc(struct hnae_ring *ring, void *priv, int size, dma_addr_t dma, int frag_end, int buf_num, enum hns_desc_type type, int mtu)
{ int frag_buf_num; int sizeoflast; int k;
wmb(); /* commit all data before submit */
assert(skb->queue_mapping < priv->ae_handle->q_num);
hnae_queue_xmit(priv->ae_handle->qs[skb->queue_mapping], buf_num);
return NETDEV_TX_OK;
out_map_frag_fail:
while (ring->next_to_use != next_to_use) {
unfill_desc(ring); if (ring->next_to_use != next_to_use)
dma_unmap_page(dev,
ring->desc_cb[ring->next_to_use].dma,
ring->desc_cb[ring->next_to_use].length,
DMA_TO_DEVICE); else
dma_unmap_single(dev,
ring->desc_cb[next_to_use].dma,
ring->desc_cb[next_to_use].length,
DMA_TO_DEVICE);
}
out_err_tx_ok:
dev_kfree_skb_any(skb); return NETDEV_TX_OK;
out_net_tx_busy:
netif_stop_subqueue(ndev, skb->queue_mapping);
/* Herbert's original patch had: * smp_mb__after_netif_stop_queue(); * but since that doesn't exist yet, just open code it.
*/
smp_mb(); return NETDEV_TX_BUSY;
}
staticvoid hns_nic_reuse_page(struct sk_buff *skb, int i, struct hnae_ring *ring, int pull_len, struct hnae_desc_cb *desc_cb)
{ struct hnae_desc *desc;
u32 truesize; int size; int last_offset; bool twobufs;
if (twobufs) { /* if we are only owner of page we can reuse it */ if (likely(page_count(desc_cb->priv) == 1)) { /* flip page offset to other buffer */
desc_cb->page_offset ^= truesize;
desc_cb->reuse_flag = 1; /* bump ref count on page before it is given*/
get_page(desc_cb->priv);
} return;
}
/* move offset up to the next cache line */
desc_cb->page_offset += truesize;
if (desc_cb->page_offset <= last_offset) {
desc_cb->reuse_flag = 1; /* bump ref count on page before it is given*/
get_page(desc_cb->priv);
}
}
/* check if RX checksum offload is enabled */ if (unlikely(!(netdev->features & NETIF_F_RXCSUM))) return;
/* In hardware, we only support checksum for the following protocols: * 1) IPv4, * 2) TCP(over IPv4 or IPv6), * 3) UDP(over IPv4 or IPv6), * 4) SCTP(over IPv4 or IPv6) * but we support many L3(IPv4, IPv6, MPLS, PPPoE etc) and L4(TCP, * UDP, GRE, SCTP, IGMP, ICMP etc.) protocols. * * Hardware limitation: * Our present hardware RX Descriptor lacks L3/L4 checksum "Status & * Error" bit (which usually can be used to indicate whether checksum * was calculated by the hardware and if there was any error encountered * during checksum calculation). * * Software workaround: * We do get info within the RX descriptor about the kind of L3/L4 * protocol coming in the packet and the error status. These errors * might not just be checksum errors but could be related to version, * length of IPv4, UDP, TCP etc. * Because there is no-way of knowing if it is a L3/L4 error due to bad * checksum or any other L3/L4 error, we will not (cannot) convey * checksum status for such cases to upper stack and will not maintain * the RX L3/L4 checksum counters as well.
*/
if (length <= HNS_RX_HEAD_SIZE) {
memcpy(__skb_put(skb, length), va, ALIGN(length, sizeof(long)));
/* we can reuse buffer as-is, just make sure it is local */ if (likely(page_to_nid(desc_cb->priv) == numa_node_id()))
desc_cb->reuse_flag = 1; else/* this page cannot be reused so discard it */
put_page(desc_cb->priv);
/* indicate to upper stack if our hardware has already calculated * the RX checksum
*/
hns_nic_rx_checksum(ring_data, skb, bnum_flag);
return 0;
}
staticvoid
hns_nic_alloc_rx_buffers(struct hns_nic_ring_data *ring_data, int cleand_count)
{ int i, ret; struct hnae_desc_cb res_cbs; struct hnae_desc_cb *desc_cb; struct hnae_ring *ring = ring_data->ring; struct net_device *ndev = ring_data->napi.dev;
for (i = 0; i < cleand_count; i++) {
desc_cb = &ring->desc_cb[ring->next_to_use]; if (desc_cb->reuse_flag) {
ring->stats.reuse_pg_cnt++;
hnae_reuse_buffer(ring, ring->next_to_use);
} else {
ret = hnae_reserve_buffer_map(ring, &res_cbs); if (ret) {
ring->stats.sw_err_cnt++;
netdev_err(ndev, "hnae reserve buffer map failed.\n"); break;
}
hnae_replace_buffer(ring, ring->next_to_use, &res_cbs);
}
ring_ptr_move_fw(ring, next_to_use);
}
wmb(); /* make all data has been write before submit */
writel_relaxed(i, ring->io_base + RCB_REG_HEAD);
}
/* return error number for error or number of desc left to take
*/ staticvoid hns_nic_rx_up_pro(struct hns_nic_ring_data *ring_data, struct sk_buff *skb)
{ struct net_device *ndev = ring_data->napi.dev;
/** * Because all ring in one port has one coalesce param, when one ring * calculate its own coalesce param, it cannot write to hardware at * once. There are three conditions as follows: * 1. current ring's coalesce param is larger than the hardware. * 2. or ring which adapt last time can change again. * 3. timeout.
*/ if (new_coal_param == handle->coal_param) {
handle->coal_last_jiffies = jiffies;
handle->coal_ring_idx = ring_data->queue_index;
} elseif (new_coal_param > handle->coal_param ||
handle->coal_ring_idx == ring_data->queue_index ||
time_after(jiffies, handle->coal_last_jiffies + (HZ >> 4))) {
handle->dev->ops->set_coalesce_usecs(handle,
new_coal_param);
handle->dev->ops->set_coalesce_frames(handle,
1, new_coal_param);
handle->coal_param = new_coal_param;
handle->coal_ring_idx = ring_data->queue_index;
handle->coal_last_jiffies = jiffies;
}
}
staticint hns_nic_rx_poll_one(struct hns_nic_ring_data *ring_data, int budget, void *v)
{ struct hnae_ring *ring = ring_data->ring; struct sk_buff *skb; int num, bnum; #define RCB_NOF_ALLOC_RX_BUFF_ONCE 16 int recv_pkts, recv_bds, clean_count, err; int unused_count = hns_desc_unused(ring);
num = readl_relaxed(ring->io_base + RCB_REG_FBDNUM);
rmb(); /* make sure num taken effect before the other data is touched */
/* poll one pkt */
err = hns_nic_poll_rx_skb(ring_data, &skb, &bnum); if (unlikely(!skb)) /* this fault cannot be repaired */ goto out;
recv_bds += bnum;
clean_count += bnum; if (unlikely(err)) { /* do jump the err */
recv_pkts++; continue;
}
/* do update ip stack process*/
((void (*)(struct hns_nic_ring_data *, struct sk_buff *))v)(
ring_data, skb);
recv_pkts++;
}
out: /* make all data has been write before submit */ if (clean_count + unused_count > 0)
hns_nic_alloc_rx_buffers(ring_data,
clean_count + unused_count);
hns_update_rx_rate(ring);
num = readl_relaxed(ring->io_base + RCB_REG_FBDNUM);
if (num <= hns_coal_rx_bdnum(ring)) { if (ring->q->handle->coal_adapt_en)
hns_nic_adpt_coalesce(ring_data);
returntrue;
}
returnfalse;
}
staticinlinevoid hns_nic_reclaim_one_desc(struct hnae_ring *ring, int *bytes, int *pkts)
{ struct hnae_desc_cb *desc_cb = &ring->desc_cb[ring->next_to_clean];
(*pkts) += (desc_cb->type == DESC_TYPE_SKB);
(*bytes) += desc_cb->length; /* desc_cb will be cleaned, after hnae_free_buffer_detach*/
hnae_free_buffer_detach(ring, ring->next_to_clean);
ring_ptr_move_fw(ring, next_to_clean);
}
staticint is_valid_clean_head(struct hnae_ring *ring, int h)
{ int u = ring->next_to_use; int c = ring->next_to_clean;
if (unlikely(h > ring->desc_num)) return 0;
assert(u > 0 && u < ring->desc_num);
assert(c > 0 && c < ring->desc_num);
assert(u != c && h != c); /* must be checked before call this func */
return u > c ? (h > c && h <= u) : (h > c || h <= u);
}
/* reclaim all desc in one budget * return error or number of desc left
*/ staticint hns_nic_tx_poll_one(struct hns_nic_ring_data *ring_data, int budget, void *v)
{ struct hnae_ring *ring = ring_data->ring; struct net_device *ndev = ring_data->napi.dev; struct netdev_queue *dev_queue; struct hns_nic_priv *priv = netdev_priv(ndev); int head; int bytes, pkts;
head = readl_relaxed(ring->io_base + RCB_REG_HEAD);
rmb(); /* make sure head is ready before touch any data */
if (is_ring_empty(ring) || head == ring->next_to_clean) return 0; /* no data to poll */
if (!is_valid_clean_head(ring, head)) {
netdev_err(ndev, "wrong head (%d, %d-%d)\n", head,
ring->next_to_use, ring->next_to_clean);
ring->stats.io_err_cnt++; return -EIO;
}
bytes = 0;
pkts = 0; while (head != ring->next_to_clean) {
hns_nic_reclaim_one_desc(ring, &bytes, &pkts); /* issue prefetch for next Tx descriptor */
prefetch(&ring->desc_cb[ring->next_to_clean]);
} /* update tx ring statistics. */
ring->stats.tx_pkts += pkts;
ring->stats.tx_bytes += bytes;
if (unlikely(priv->link && !netif_carrier_ok(ndev)))
netif_carrier_on(ndev);
if (unlikely(pkts && netif_carrier_ok(ndev) &&
(ring_space(ring) >= ring->max_desc_num_per_pkt * 2))) { /* Make sure that anybody stopping the queue after this * sees the new next_to_clean.
*/
smp_mb(); if (netif_tx_queue_stopped(dev_queue) &&
!test_bit(NIC_STATE_DOWN, &priv->state)) {
netif_tx_wake_queue(dev_queue);
ring->stats.restart_queue++;
}
} return 0;
}
/** *hns_nic_adjust_link - adjust net work mode by the phy stat or new param *@ndev: net device
*/ staticvoid hns_nic_adjust_link(struct net_device *ndev)
{ struct hns_nic_priv *priv = netdev_priv(ndev); struct hnae_handle *h = priv->ae_handle; int state = 1;
/* If there is no phy, do not need adjust link */ if (ndev->phydev) { /* When phy link down, do nothing */ if (ndev->phydev->link == 0) return;
if (h->dev->ops->need_adjust_link(h, ndev->phydev->speed,
ndev->phydev->duplex)) { /* because Hi161X chip don't support to change gmac * speed and duplex with traffic. Delay 200ms to * make sure there is no more data in chip FIFO.
*/
netif_carrier_off(ndev);
msleep(200);
h->dev->ops->adjust_link(h, ndev->phydev->speed,
ndev->phydev->duplex);
netif_carrier_on(ndev);
}
}
/* set mac addr if it is configed. or leave it to the AE driver */ staticvoid hns_init_mac_addr(struct net_device *ndev)
{ struct hns_nic_priv *priv = netdev_priv(ndev);
if (device_get_ethdev_address(priv->dev, ndev)) {
eth_hw_addr_random(ndev);
dev_warn(priv->dev, "No valid mac, use random mac %pM",
ndev->dev_addr);
}
}
staticint hns_nic_init_affinity_mask(int q_num, int ring_idx, struct hnae_ring *ring, cpumask_t *mask)
{ int cpu;
/* Different irq balance between 16core and 32core. * The cpu mask set by ring index according to the ring flag * which indicate the ring is tx or rx.
*/ if (q_num == num_possible_cpus()) { if (is_tx_ring(ring))
cpu = ring_idx; else
cpu = ring_idx - q_num;
} else { if (is_tx_ring(ring))
cpu = ring_idx * 2; else
cpu = (ring_idx - q_num) * 2 + 1;
}
cpumask_clear(mask);
cpumask_set_cpu(cpu, mask);
return cpu;
}
staticvoid hns_nic_free_irq(int q_num, struct hns_nic_priv *priv)
{ int i;
for (i = 0; i < q_num * 2; i++) { if (priv->ring_data[i].ring->irq_init_flag == RCB_IRQ_INITED) {
irq_set_affinity_hint(priv->ring_data[i].ring->irq,
NULL);
free_irq(priv->ring_data[i].ring->irq,
&priv->ring_data[i]);
priv->ring_data[i].ring->irq_init_flag =
RCB_IRQ_NOT_INITED;
}
}
}
staticint hns_nic_init_irq(struct hns_nic_priv *priv)
{ struct hnae_handle *h = priv->ae_handle; struct hns_nic_ring_data *rd; int i; int ret; int cpu;
for (i = 0; i < h->q_num * 2; i++) {
rd = &priv->ring_data[i];
if (rd->ring->irq_init_flag == RCB_IRQ_INITED) break;
/** *hns_nic_clear_all_rx_fetch - clear the chip fetched descriptions. The *function as follows: * 1. if one rx ring has found the page_offset is not equal 0 between head * and tail, it means that the chip fetched the wrong descs for the ring * which buffer size is 4096. * 2. we set the chip serdes loopback and set rss indirection to the ring. * 3. construct 64-bytes ip broadcast packages, wait the associated rx ring * receiving all packages and it will fetch new descriptions. * 4. recover to the original state. * *@ndev: net device
*/ staticint hns_nic_clear_all_rx_fetch(struct net_device *ndev)
{ struct hns_nic_priv *priv = netdev_priv(ndev); struct hnae_handle *h = priv->ae_handle; struct hnae_ae_ops *ops = h->dev->ops; struct hns_nic_ring_data *rd; struct hnae_ring *ring; struct sk_buff *skb;
u32 *org_indir;
u32 *cur_indir; int indir_size; int head, tail; int fetch_num; int i, j; bool found; int retry_times; int ret = 0;
/* store the original indirection */
ops->get_rss(h, org_indir, NULL, NULL);
cur_indir = kzalloc(indir_size, GFP_KERNEL); if (!cur_indir) {
ret = -ENOMEM; goto cur_indir_alloc_err;
}
/* set loopback */ if (hns_enable_serdes_lb(ndev)) {
ret = -EINVAL; goto enable_serdes_lb_err;
}
/* foreach every rx ring to clear fetch desc */ for (i = 0; i < h->q_num; i++) {
ring = &h->qs[i]->rx_ring;
head = readl_relaxed(ring->io_base + RCB_REG_HEAD);
tail = readl_relaxed(ring->io_base + RCB_REG_TAIL);
found = false;
fetch_num = ring_dist(ring, head, tail);
while (head != tail) { if (ring->desc_cb[head].page_offset != 0) {
found = true; break;
}
head++; if (head == ring->desc_num)
head = 0;
}
if (found) { for (j = 0; j < indir_size / sizeof(*org_indir); j++)
cur_indir[j] = i;
ops->set_rss(h, cur_indir, NULL, 0);
for (j = 0; j < fetch_num; j++) { /* alloc one skb and init */
skb = hns_assemble_skb(ndev); if (!skb) {
ret = -ENOMEM; goto out;
}
rd = &tx_ring_data(priv, skb->queue_mapping);
hns_nic_net_xmit_hw(ndev, skb, rd);
if (ops->get_regs_len && ops->get_regs) {
reg_num = ops->get_regs_len(priv->ae_handle);
reg_num = (reg_num + 3ul) & ~3ul;
data = kcalloc(reg_num, sizeof(u32), GFP_KERNEL); if (data) {
ops->get_regs(priv->ae_handle, data); for (i = 0; i < reg_num; i += 4)
pr_info("0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x\n",
i, data[i], data[i + 1],
data[i + 2], data[i + 3]);
kfree(data);
}
}
for (i = 0; i < h->q_num; i++) {
pr_info("tx_queue%d_next_to_clean:%d\n",
i, h->qs[i]->tx_ring.next_to_clean);
pr_info("tx_queue%d_next_to_use:%d\n",
i, h->qs[i]->tx_ring.next_to_use);
pr_info("rx_queue%d_next_to_clean:%d\n",
i, h->qs[i]->rx_ring.next_to_clean);
pr_info("rx_queue%d_next_to_use:%d\n",
i, h->qs[i]->rx_ring.next_to_use);
}
}
/* for resetting subtask */ staticvoid hns_nic_reset_subtask(struct hns_nic_priv *priv)
{ enum hnae_port_type type = priv->ae_handle->port_type;
if (!test_bit(NIC_STATE2_RESET_REQUESTED, &priv->state)) return;
clear_bit(NIC_STATE2_RESET_REQUESTED, &priv->state);
/* If we're already down, removing or resetting, just bail */ if (test_bit(NIC_STATE_DOWN, &priv->state) ||
test_bit(NIC_STATE_REMOVING, &priv->state) ||
test_bit(NIC_STATE_RESETTING, &priv->state)) return;
rtnl_lock(); /* put off any impending NetWatchDogTimeout */
netif_trans_update(priv->netdev);
hns_nic_net_reinit(priv->netdev);
rtnl_unlock();
}
/* for doing service complete*/ staticvoid hns_nic_service_event_complete(struct hns_nic_priv *priv)
{
WARN_ON(!test_bit(NIC_STATE_SERVICE_SCHED, &priv->state)); /* make sure to commit the things */
smp_mb__before_atomic();
clear_bit(NIC_STATE_SERVICE_SCHED, &priv->state);
}
if (acpi_dev_found(hns_enet_acpi_match[0].id))
priv->enet_ver = AE_VERSION_1; elseif (acpi_dev_found(hns_enet_acpi_match[1].id))
priv->enet_ver = AE_VERSION_2; else {
ret = -ENXIO; goto out_read_prop_fail;
}
/* try to find port-idx-in-ae first */
ret = acpi_node_get_property_reference(dev->fwnode, "ae-handle", 0, &args); if (ret) {
dev_err(dev, "not find ae-handle\n"); goto out_read_prop_fail;
} if (!is_acpi_device_node(args.fwnode)) {
ret = -EINVAL; goto out_read_prop_fail;
}
priv->fwnode = args.fwnode;
} else {
dev_err(dev, "cannot read cfg data from OF or acpi\n");
ret = -ENXIO; goto out_read_prop_fail;
}
ret = device_property_read_u32(dev, "port-idx-in-ae", &port_id); if (ret) { /* only for old code compatible */
ret = device_property_read_u32(dev, "port-id", &port_id); if (ret) goto out_read_prop_fail; /* for old dts, we need to caculate the port offset */
port_id = port_id < HNS_SRV_OFFSET ? port_id + HNS_DEBUG_OFFSET
: port_id - HNS_SRV_OFFSET;
}
priv->port_id = port_id;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.