162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (c) 2014-2015 Hisilicon Limited.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/dma-mapping.h>
762306a36Sopenharmony_ci#include <linux/interrupt.h>
862306a36Sopenharmony_ci#include <linux/of.h>
962306a36Sopenharmony_ci#include <linux/skbuff.h>
1062306a36Sopenharmony_ci#include <linux/slab.h>
1162306a36Sopenharmony_ci#include "hnae.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define cls_to_ae_dev(dev) container_of(dev, struct hnae_ae_dev, cls_dev)
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic struct class *hnae_class;
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistatic void
1862306a36Sopenharmony_cihnae_list_add(spinlock_t *lock, struct list_head *node, struct list_head *head)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	unsigned long flags;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci	spin_lock_irqsave(lock, flags);
2362306a36Sopenharmony_ci	list_add_tail_rcu(node, head);
2462306a36Sopenharmony_ci	spin_unlock_irqrestore(lock, flags);
2562306a36Sopenharmony_ci}
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_cistatic void hnae_list_del(spinlock_t *lock, struct list_head *node)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	unsigned long flags;
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci	spin_lock_irqsave(lock, flags);
3262306a36Sopenharmony_ci	list_del_rcu(node);
3362306a36Sopenharmony_ci	spin_unlock_irqrestore(lock, flags);
3462306a36Sopenharmony_ci}
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic int hnae_alloc_buffer(struct hnae_ring *ring, struct hnae_desc_cb *cb)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	unsigned int order = hnae_page_order(ring);
3962306a36Sopenharmony_ci	struct page *p = dev_alloc_pages(order);
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	if (!p)
4262306a36Sopenharmony_ci		return -ENOMEM;
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	cb->priv = p;
4562306a36Sopenharmony_ci	cb->page_offset = 0;
4662306a36Sopenharmony_ci	cb->reuse_flag = 0;
4762306a36Sopenharmony_ci	cb->buf  = page_address(p);
4862306a36Sopenharmony_ci	cb->length = hnae_page_size(ring);
4962306a36Sopenharmony_ci	cb->type = DESC_TYPE_PAGE;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	return 0;
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic void hnae_free_buffer(struct hnae_ring *ring, struct hnae_desc_cb *cb)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	if (unlikely(!cb->priv))
5762306a36Sopenharmony_ci		return;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	if (cb->type == DESC_TYPE_SKB)
6062306a36Sopenharmony_ci		dev_kfree_skb_any((struct sk_buff *)cb->priv);
6162306a36Sopenharmony_ci	else if (unlikely(is_rx_ring(ring)))
6262306a36Sopenharmony_ci		put_page((struct page *)cb->priv);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	cb->priv = NULL;
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic int hnae_map_buffer(struct hnae_ring *ring, struct hnae_desc_cb *cb)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	cb->dma = dma_map_page(ring_to_dev(ring), cb->priv, 0,
7062306a36Sopenharmony_ci			       cb->length, ring_to_dma_dir(ring));
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci	if (dma_mapping_error(ring_to_dev(ring), cb->dma))
7362306a36Sopenharmony_ci		return -EIO;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	return 0;
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic void hnae_unmap_buffer(struct hnae_ring *ring, struct hnae_desc_cb *cb)
7962306a36Sopenharmony_ci{
8062306a36Sopenharmony_ci	if (cb->type == DESC_TYPE_SKB)
8162306a36Sopenharmony_ci		dma_unmap_single(ring_to_dev(ring), cb->dma, cb->length,
8262306a36Sopenharmony_ci				 ring_to_dma_dir(ring));
8362306a36Sopenharmony_ci	else if (cb->length)
8462306a36Sopenharmony_ci		dma_unmap_page(ring_to_dev(ring), cb->dma, cb->length,
8562306a36Sopenharmony_ci			       ring_to_dma_dir(ring));
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic struct hnae_buf_ops hnae_bops = {
8962306a36Sopenharmony_ci	.alloc_buffer = hnae_alloc_buffer,
9062306a36Sopenharmony_ci	.free_buffer = hnae_free_buffer,
9162306a36Sopenharmony_ci	.map_buffer = hnae_map_buffer,
9262306a36Sopenharmony_ci	.unmap_buffer = hnae_unmap_buffer,
9362306a36Sopenharmony_ci};
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic int __ae_match(struct device *dev, const void *data)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	struct hnae_ae_dev *hdev = cls_to_ae_dev(dev);
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	if (dev_of_node(hdev->dev))
10062306a36Sopenharmony_ci		return (data == &hdev->dev->of_node->fwnode);
10162306a36Sopenharmony_ci	else if (is_acpi_node(hdev->dev->fwnode))
10262306a36Sopenharmony_ci		return (data == hdev->dev->fwnode);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	dev_err(dev, "__ae_match cannot read cfg data from OF or acpi\n");
10562306a36Sopenharmony_ci	return 0;
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic struct hnae_ae_dev *find_ae(const struct fwnode_handle *fwnode)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	struct device *dev;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	WARN_ON(!fwnode);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	dev = class_find_device(hnae_class, NULL, fwnode, __ae_match);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	return dev ? cls_to_ae_dev(dev) : NULL;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic void hnae_free_buffers(struct hnae_ring *ring)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	int i;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci	for (i = 0; i < ring->desc_num; i++)
12462306a36Sopenharmony_ci		hnae_free_buffer_detach(ring, i);
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci/* Allocate memory for raw pkg, and map with dma */
12862306a36Sopenharmony_cistatic int hnae_alloc_buffers(struct hnae_ring *ring)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	int i, j, ret;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	for (i = 0; i < ring->desc_num; i++) {
13362306a36Sopenharmony_ci		ret = hnae_alloc_buffer_attach(ring, i);
13462306a36Sopenharmony_ci		if (ret)
13562306a36Sopenharmony_ci			goto out_buffer_fail;
13662306a36Sopenharmony_ci	}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	return 0;
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ciout_buffer_fail:
14162306a36Sopenharmony_ci	for (j = i - 1; j >= 0; j--)
14262306a36Sopenharmony_ci		hnae_free_buffer_detach(ring, j);
14362306a36Sopenharmony_ci	return ret;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/* free desc along with its attached buffer */
14762306a36Sopenharmony_cistatic void hnae_free_desc(struct hnae_ring *ring)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	dma_unmap_single(ring_to_dev(ring), ring->desc_dma_addr,
15062306a36Sopenharmony_ci			 ring->desc_num * sizeof(ring->desc[0]),
15162306a36Sopenharmony_ci			 ring_to_dma_dir(ring));
15262306a36Sopenharmony_ci	ring->desc_dma_addr = 0;
15362306a36Sopenharmony_ci	kfree(ring->desc);
15462306a36Sopenharmony_ci	ring->desc = NULL;
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci/* alloc desc, without buffer attached */
15862306a36Sopenharmony_cistatic int hnae_alloc_desc(struct hnae_ring *ring)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	int size = ring->desc_num * sizeof(ring->desc[0]);
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	ring->desc = kzalloc(size, GFP_KERNEL);
16362306a36Sopenharmony_ci	if (!ring->desc)
16462306a36Sopenharmony_ci		return -ENOMEM;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	ring->desc_dma_addr = dma_map_single(ring_to_dev(ring),
16762306a36Sopenharmony_ci		ring->desc, size, ring_to_dma_dir(ring));
16862306a36Sopenharmony_ci	if (dma_mapping_error(ring_to_dev(ring), ring->desc_dma_addr)) {
16962306a36Sopenharmony_ci		ring->desc_dma_addr = 0;
17062306a36Sopenharmony_ci		kfree(ring->desc);
17162306a36Sopenharmony_ci		ring->desc = NULL;
17262306a36Sopenharmony_ci		return -ENOMEM;
17362306a36Sopenharmony_ci	}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	return 0;
17662306a36Sopenharmony_ci}
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci/* fini ring, also free the buffer for the ring */
17962306a36Sopenharmony_cistatic void hnae_fini_ring(struct hnae_ring *ring)
18062306a36Sopenharmony_ci{
18162306a36Sopenharmony_ci	if (is_rx_ring(ring))
18262306a36Sopenharmony_ci		hnae_free_buffers(ring);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	hnae_free_desc(ring);
18562306a36Sopenharmony_ci	kfree(ring->desc_cb);
18662306a36Sopenharmony_ci	ring->desc_cb = NULL;
18762306a36Sopenharmony_ci	ring->next_to_clean = 0;
18862306a36Sopenharmony_ci	ring->next_to_use = 0;
18962306a36Sopenharmony_ci}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci/* init ring, and with buffer for rx ring */
19262306a36Sopenharmony_cistatic int
19362306a36Sopenharmony_cihnae_init_ring(struct hnae_queue *q, struct hnae_ring *ring, int flags)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	int ret;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	if (ring->desc_num <= 0 || ring->buf_size <= 0)
19862306a36Sopenharmony_ci		return -EINVAL;
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	ring->q = q;
20162306a36Sopenharmony_ci	ring->flags = flags;
20262306a36Sopenharmony_ci	ring->coal_param = q->handle->coal_param;
20362306a36Sopenharmony_ci	assert(!ring->desc && !ring->desc_cb && !ring->desc_dma_addr);
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	/* not matter for tx or rx ring, the ntc and ntc start from 0 */
20662306a36Sopenharmony_ci	assert(ring->next_to_use == 0);
20762306a36Sopenharmony_ci	assert(ring->next_to_clean == 0);
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	ring->desc_cb = kcalloc(ring->desc_num, sizeof(ring->desc_cb[0]),
21062306a36Sopenharmony_ci			GFP_KERNEL);
21162306a36Sopenharmony_ci	if (!ring->desc_cb) {
21262306a36Sopenharmony_ci		ret = -ENOMEM;
21362306a36Sopenharmony_ci		goto out;
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	ret = hnae_alloc_desc(ring);
21762306a36Sopenharmony_ci	if (ret)
21862306a36Sopenharmony_ci		goto out_with_desc_cb;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	if (is_rx_ring(ring)) {
22162306a36Sopenharmony_ci		ret = hnae_alloc_buffers(ring);
22262306a36Sopenharmony_ci		if (ret)
22362306a36Sopenharmony_ci			goto out_with_desc;
22462306a36Sopenharmony_ci	}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	return 0;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ciout_with_desc:
22962306a36Sopenharmony_ci	hnae_free_desc(ring);
23062306a36Sopenharmony_ciout_with_desc_cb:
23162306a36Sopenharmony_ci	kfree(ring->desc_cb);
23262306a36Sopenharmony_ci	ring->desc_cb = NULL;
23362306a36Sopenharmony_ciout:
23462306a36Sopenharmony_ci	return ret;
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic int hnae_init_queue(struct hnae_handle *h, struct hnae_queue *q,
23862306a36Sopenharmony_ci			   struct hnae_ae_dev *dev)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	int ret;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	q->dev = dev;
24362306a36Sopenharmony_ci	q->handle = h;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	ret = hnae_init_ring(q, &q->tx_ring, q->tx_ring.flags | RINGF_DIR);
24662306a36Sopenharmony_ci	if (ret)
24762306a36Sopenharmony_ci		goto out;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	ret = hnae_init_ring(q, &q->rx_ring, q->rx_ring.flags & ~RINGF_DIR);
25062306a36Sopenharmony_ci	if (ret)
25162306a36Sopenharmony_ci		goto out_with_tx_ring;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	if (dev->ops->init_queue)
25462306a36Sopenharmony_ci		dev->ops->init_queue(q);
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	return 0;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ciout_with_tx_ring:
25962306a36Sopenharmony_ci	hnae_fini_ring(&q->tx_ring);
26062306a36Sopenharmony_ciout:
26162306a36Sopenharmony_ci	return ret;
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_cistatic void hnae_fini_queue(struct hnae_queue *q)
26562306a36Sopenharmony_ci{
26662306a36Sopenharmony_ci	if (q->dev->ops->fini_queue)
26762306a36Sopenharmony_ci		q->dev->ops->fini_queue(q);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	hnae_fini_ring(&q->tx_ring);
27062306a36Sopenharmony_ci	hnae_fini_ring(&q->rx_ring);
27162306a36Sopenharmony_ci}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci/*
27462306a36Sopenharmony_ci * ae_chain - define ae chain head
27562306a36Sopenharmony_ci */
27662306a36Sopenharmony_cistatic RAW_NOTIFIER_HEAD(ae_chain);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ciint hnae_register_notifier(struct notifier_block *nb)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	return raw_notifier_chain_register(&ae_chain, nb);
28162306a36Sopenharmony_ci}
28262306a36Sopenharmony_ciEXPORT_SYMBOL(hnae_register_notifier);
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_civoid hnae_unregister_notifier(struct notifier_block *nb)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	if (raw_notifier_chain_unregister(&ae_chain, nb))
28762306a36Sopenharmony_ci		dev_err(NULL, "notifier chain unregister fail\n");
28862306a36Sopenharmony_ci}
28962306a36Sopenharmony_ciEXPORT_SYMBOL(hnae_unregister_notifier);
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_ciint hnae_reinit_handle(struct hnae_handle *handle)
29262306a36Sopenharmony_ci{
29362306a36Sopenharmony_ci	int i, j;
29462306a36Sopenharmony_ci	int ret;
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ci	for (i = 0; i < handle->q_num; i++) /* free ring*/
29762306a36Sopenharmony_ci		hnae_fini_queue(handle->qs[i]);
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	if (handle->dev->ops->reset)
30062306a36Sopenharmony_ci		handle->dev->ops->reset(handle);
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	for (i = 0; i < handle->q_num; i++) {/* reinit ring*/
30362306a36Sopenharmony_ci		ret = hnae_init_queue(handle, handle->qs[i], handle->dev);
30462306a36Sopenharmony_ci		if (ret)
30562306a36Sopenharmony_ci			goto out_when_init_queue;
30662306a36Sopenharmony_ci	}
30762306a36Sopenharmony_ci	return 0;
30862306a36Sopenharmony_ciout_when_init_queue:
30962306a36Sopenharmony_ci	for (j = i - 1; j >= 0; j--)
31062306a36Sopenharmony_ci		hnae_fini_queue(handle->qs[j]);
31162306a36Sopenharmony_ci	return ret;
31262306a36Sopenharmony_ci}
31362306a36Sopenharmony_ciEXPORT_SYMBOL(hnae_reinit_handle);
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci/* hnae_get_handle - get a handle from the AE
31662306a36Sopenharmony_ci * @owner_dev: the dev use this handle
31762306a36Sopenharmony_ci * @ae_id: the id of the ae to be used
31862306a36Sopenharmony_ci * @ae_opts: the options set for the handle
31962306a36Sopenharmony_ci * @bops: the callbacks for buffer management
32062306a36Sopenharmony_ci *
32162306a36Sopenharmony_ci * return handle ptr or ERR_PTR
32262306a36Sopenharmony_ci */
32362306a36Sopenharmony_cistruct hnae_handle *hnae_get_handle(struct device *owner_dev,
32462306a36Sopenharmony_ci				    const struct fwnode_handle	*fwnode,
32562306a36Sopenharmony_ci				    u32 port_id,
32662306a36Sopenharmony_ci				    struct hnae_buf_ops *bops)
32762306a36Sopenharmony_ci{
32862306a36Sopenharmony_ci	struct hnae_ae_dev *dev;
32962306a36Sopenharmony_ci	struct hnae_handle *handle;
33062306a36Sopenharmony_ci	int i, j;
33162306a36Sopenharmony_ci	int ret;
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	dev = find_ae(fwnode);
33462306a36Sopenharmony_ci	if (!dev)
33562306a36Sopenharmony_ci		return ERR_PTR(-ENODEV);
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci	handle = dev->ops->get_handle(dev, port_id);
33862306a36Sopenharmony_ci	if (IS_ERR(handle)) {
33962306a36Sopenharmony_ci		put_device(&dev->cls_dev);
34062306a36Sopenharmony_ci		return handle;
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	handle->dev = dev;
34462306a36Sopenharmony_ci	handle->owner_dev = owner_dev;
34562306a36Sopenharmony_ci	handle->bops = bops ? bops : &hnae_bops;
34662306a36Sopenharmony_ci	handle->eport_id = port_id;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	for (i = 0; i < handle->q_num; i++) {
34962306a36Sopenharmony_ci		ret = hnae_init_queue(handle, handle->qs[i], dev);
35062306a36Sopenharmony_ci		if (ret)
35162306a36Sopenharmony_ci			goto out_when_init_queue;
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	__module_get(dev->owner);
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	hnae_list_add(&dev->lock, &handle->node, &dev->handle_list);
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	return handle;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ciout_when_init_queue:
36162306a36Sopenharmony_ci	for (j = i - 1; j >= 0; j--)
36262306a36Sopenharmony_ci		hnae_fini_queue(handle->qs[j]);
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_ci	put_device(&dev->cls_dev);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	return ERR_PTR(-ENOMEM);
36762306a36Sopenharmony_ci}
36862306a36Sopenharmony_ciEXPORT_SYMBOL(hnae_get_handle);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_civoid hnae_put_handle(struct hnae_handle *h)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	struct hnae_ae_dev *dev = h->dev;
37362306a36Sopenharmony_ci	int i;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	for (i = 0; i < h->q_num; i++)
37662306a36Sopenharmony_ci		hnae_fini_queue(h->qs[i]);
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci	if (h->dev->ops->reset)
37962306a36Sopenharmony_ci		h->dev->ops->reset(h);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	hnae_list_del(&dev->lock, &h->node);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	if (dev->ops->put_handle)
38462306a36Sopenharmony_ci		dev->ops->put_handle(h);
38562306a36Sopenharmony_ci
38662306a36Sopenharmony_ci	module_put(dev->owner);
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	put_device(&dev->cls_dev);
38962306a36Sopenharmony_ci}
39062306a36Sopenharmony_ciEXPORT_SYMBOL(hnae_put_handle);
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_cistatic void hnae_release(struct device *dev)
39362306a36Sopenharmony_ci{
39462306a36Sopenharmony_ci}
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci/**
39762306a36Sopenharmony_ci * hnae_ae_register - register a AE engine to hnae framework
39862306a36Sopenharmony_ci * @hdev: the hnae ae engine device
39962306a36Sopenharmony_ci * @owner:  the module who provides this dev
40062306a36Sopenharmony_ci * NOTE: the duplicated name will not be checked
40162306a36Sopenharmony_ci */
40262306a36Sopenharmony_ciint hnae_ae_register(struct hnae_ae_dev *hdev, struct module *owner)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	static atomic_t id = ATOMIC_INIT(-1);
40562306a36Sopenharmony_ci	int ret;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	if (!hdev->dev)
40862306a36Sopenharmony_ci		return -ENODEV;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	if (!hdev->ops || !hdev->ops->get_handle ||
41162306a36Sopenharmony_ci	    !hdev->ops->toggle_ring_irq ||
41262306a36Sopenharmony_ci	    !hdev->ops->get_status || !hdev->ops->adjust_link)
41362306a36Sopenharmony_ci		return -EINVAL;
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	hdev->owner = owner;
41662306a36Sopenharmony_ci	hdev->id = (int)atomic_inc_return(&id);
41762306a36Sopenharmony_ci	hdev->cls_dev.parent = hdev->dev;
41862306a36Sopenharmony_ci	hdev->cls_dev.class = hnae_class;
41962306a36Sopenharmony_ci	hdev->cls_dev.release = hnae_release;
42062306a36Sopenharmony_ci	(void)dev_set_name(&hdev->cls_dev, "hnae%d", hdev->id);
42162306a36Sopenharmony_ci	ret = device_register(&hdev->cls_dev);
42262306a36Sopenharmony_ci	if (ret) {
42362306a36Sopenharmony_ci		put_device(&hdev->cls_dev);
42462306a36Sopenharmony_ci		return ret;
42562306a36Sopenharmony_ci	}
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	INIT_LIST_HEAD(&hdev->handle_list);
42862306a36Sopenharmony_ci	spin_lock_init(&hdev->lock);
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	ret = raw_notifier_call_chain(&ae_chain, HNAE_AE_REGISTER, NULL);
43162306a36Sopenharmony_ci	if (ret)
43262306a36Sopenharmony_ci		dev_dbg(hdev->dev,
43362306a36Sopenharmony_ci			"has not notifier for AE: %s\n", hdev->name);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	return 0;
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ciEXPORT_SYMBOL(hnae_ae_register);
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci/**
44062306a36Sopenharmony_ci * hnae_ae_unregister - unregisters a HNAE AE engine
44162306a36Sopenharmony_ci * @hdev: the device to unregister
44262306a36Sopenharmony_ci */
44362306a36Sopenharmony_civoid hnae_ae_unregister(struct hnae_ae_dev *hdev)
44462306a36Sopenharmony_ci{
44562306a36Sopenharmony_ci	device_unregister(&hdev->cls_dev);
44662306a36Sopenharmony_ci}
44762306a36Sopenharmony_ciEXPORT_SYMBOL(hnae_ae_unregister);
44862306a36Sopenharmony_ci
44962306a36Sopenharmony_cistatic int __init hnae_init(void)
45062306a36Sopenharmony_ci{
45162306a36Sopenharmony_ci	hnae_class = class_create("hnae");
45262306a36Sopenharmony_ci	return PTR_ERR_OR_ZERO(hnae_class);
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_cistatic void __exit hnae_exit(void)
45662306a36Sopenharmony_ci{
45762306a36Sopenharmony_ci	class_destroy(hnae_class);
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_cisubsys_initcall(hnae_init);
46162306a36Sopenharmony_cimodule_exit(hnae_exit);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ciMODULE_AUTHOR("Hisilicon, Inc.");
46462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
46562306a36Sopenharmony_ciMODULE_DESCRIPTION("Hisilicon Network Acceleration Engine Framework");
46662306a36Sopenharmony_ci
46762306a36Sopenharmony_ci/* vi: set tw=78 noet: */
468