hnae3.c 8.7 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
/*
 * Copyright (c) 2016-2017 Hisilicon Limited.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 */

#include <linux/list.h>
#include <linux/spinlock.h>

#include "hnae3.h"

static LIST_HEAD(hnae3_ae_algo_list);
static LIST_HEAD(hnae3_client_list);
static LIST_HEAD(hnae3_ae_dev_list);

/* we are keeping things simple and using single lock for all the
 * list. This is a non-critical code so other updations, if happen
 * in parallel, can wait.
 */
static DEFINE_MUTEX(hnae3_common_lock);

static bool hnae3_client_match(enum hnae3_client_type client_type,
			       enum hnae3_dev_type dev_type)
{
	if ((dev_type == HNAE3_DEV_KNIC) && (client_type == HNAE3_CLIENT_KNIC ||
					     client_type == HNAE3_CLIENT_ROCE))
		return true;

	if (dev_type == HNAE3_DEV_UNIC && client_type == HNAE3_CLIENT_UNIC)
		return true;

	return false;
}

38 39 40 41 42
static void hnae3_set_client_init_flag(struct hnae3_client *client,
				       struct hnae3_ae_dev *ae_dev, int inited)
{
	switch (client->type) {
	case HNAE3_CLIENT_KNIC:
P
Peng Li 已提交
43
		hnae3_set_bit(ae_dev->flag, HNAE3_KNIC_CLIENT_INITED_B, inited);
44 45
		break;
	case HNAE3_CLIENT_UNIC:
P
Peng Li 已提交
46
		hnae3_set_bit(ae_dev->flag, HNAE3_UNIC_CLIENT_INITED_B, inited);
47 48
		break;
	case HNAE3_CLIENT_ROCE:
P
Peng Li 已提交
49
		hnae3_set_bit(ae_dev->flag, HNAE3_ROCE_CLIENT_INITED_B, inited);
50 51 52 53 54 55 56 57 58 59 60 61 62
		break;
	default:
		break;
	}
}

static int hnae3_get_client_init_flag(struct hnae3_client *client,
				       struct hnae3_ae_dev *ae_dev)
{
	int inited = 0;

	switch (client->type) {
	case HNAE3_CLIENT_KNIC:
P
Peng Li 已提交
63
		inited = hnae3_get_bit(ae_dev->flag,
64 65 66
				       HNAE3_KNIC_CLIENT_INITED_B);
		break;
	case HNAE3_CLIENT_UNIC:
P
Peng Li 已提交
67
		inited = hnae3_get_bit(ae_dev->flag,
68 69 70
				       HNAE3_UNIC_CLIENT_INITED_B);
		break;
	case HNAE3_CLIENT_ROCE:
P
Peng Li 已提交
71 72
		inited = hnae3_get_bit(ae_dev->flag,
				       HNAE3_ROCE_CLIENT_INITED_B);
73 74 75 76 77 78 79 80
		break;
	default:
		break;
	}

	return inited;
}

81
static int hnae3_match_n_instantiate(struct hnae3_client *client,
82
				     struct hnae3_ae_dev *ae_dev, bool is_reg)
83 84 85 86 87
{
	int ret;

	/* check if this client matches the type of ae_dev */
	if (!(hnae3_client_match(client->type, ae_dev->dev_type) &&
P
Peng Li 已提交
88
	      hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))) {
89 90 91 92 93 94
		return 0;
	}

	/* now, (un-)instantiate client by calling lower layer */
	if (is_reg) {
		ret = ae_dev->ops->init_client_instance(client, ae_dev);
95
		if (ret) {
96
			dev_err(&ae_dev->pdev->dev,
97
				"fail to instantiate client, ret = %d\n", ret);
98 99 100
			return ret;
		}

101
		hnae3_set_client_init_flag(client, ae_dev, 1);
102 103 104
		return 0;
	}

105
	if (hnae3_get_client_init_flag(client, ae_dev)) {
106 107
		ae_dev->ops->uninit_client_instance(client, ae_dev);

108
		hnae3_set_client_init_flag(client, ae_dev, 0);
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
	}

	return 0;
}

int hnae3_register_client(struct hnae3_client *client)
{
	struct hnae3_client *client_tmp;
	struct hnae3_ae_dev *ae_dev;
	int ret = 0;

	mutex_lock(&hnae3_common_lock);
	/* one system should only have one client for every type */
	list_for_each_entry(client_tmp, &hnae3_client_list, node) {
		if (client_tmp->type == client->type)
			goto exit;
	}

	list_add_tail(&client->node, &hnae3_client_list);

	/* initialize the client on every matched port */
	list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
		/* if the client could not be initialized on current port, for
		 * any error reasons, move on to next available port
		 */
134
		ret = hnae3_match_n_instantiate(client, ae_dev, true);
135 136
		if (ret)
			dev_err(&ae_dev->pdev->dev,
137 138
				"match and instantiation failed for port, ret = %d\n",
				ret);
139 140 141 142 143
	}

exit:
	mutex_unlock(&hnae3_common_lock);

144
	return 0;
145 146 147 148 149 150 151 152 153 154
}
EXPORT_SYMBOL(hnae3_register_client);

void hnae3_unregister_client(struct hnae3_client *client)
{
	struct hnae3_ae_dev *ae_dev;

	mutex_lock(&hnae3_common_lock);
	/* un-initialize the client on every matched port */
	list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
155
		hnae3_match_n_instantiate(client, ae_dev, false);
156 157 158 159 160 161 162 163 164 165 166
	}

	list_del(&client->node);
	mutex_unlock(&hnae3_common_lock);
}
EXPORT_SYMBOL(hnae3_unregister_client);

/* hnae3_register_ae_algo - register a AE algorithm to hnae3 framework
 * @ae_algo: AE algorithm
 * NOTE: the duplicated name will not be checked
 */
167
void hnae3_register_ae_algo(struct hnae3_ae_algo *ae_algo)
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
{
	const struct pci_device_id *id;
	struct hnae3_ae_dev *ae_dev;
	struct hnae3_client *client;
	int ret = 0;

	mutex_lock(&hnae3_common_lock);

	list_add_tail(&ae_algo->node, &hnae3_ae_algo_list);

	/* Check if this algo/ops matches the list of ae_devs */
	list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
		id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
		if (!id)
			continue;

		/* ae_dev init should set flag */
		ae_dev->ops = ae_algo->ops;
		ret = ae_algo->ops->init_ae_dev(ae_dev);
		if (ret) {
188 189
			dev_err(&ae_dev->pdev->dev,
				"init ae_dev error, ret = %d\n", ret);
190 191 192
			continue;
		}

P
Peng Li 已提交
193
		hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1);
194 195 196 197 198

		/* check the client list for the match with this ae_dev type and
		 * initialize the figure out client instance
		 */
		list_for_each_entry(client, &hnae3_client_list, node) {
199
			ret = hnae3_match_n_instantiate(client, ae_dev, true);
200 201
			if (ret)
				dev_err(&ae_dev->pdev->dev,
202 203
					"match and instantiation failed, ret = %d\n",
					ret);
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
		}
	}

	mutex_unlock(&hnae3_common_lock);
}
EXPORT_SYMBOL(hnae3_register_ae_algo);

/* hnae3_unregister_ae_algo - unregisters a AE algorithm
 * @ae_algo: the AE algorithm to unregister
 */
void hnae3_unregister_ae_algo(struct hnae3_ae_algo *ae_algo)
{
	const struct pci_device_id *id;
	struct hnae3_ae_dev *ae_dev;
	struct hnae3_client *client;

	mutex_lock(&hnae3_common_lock);
	/* Check if there are matched ae_dev */
	list_for_each_entry(ae_dev, &hnae3_ae_dev_list, node) {
P
Peng Li 已提交
223
		if (!hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))
224 225
			continue;

226 227 228 229 230 231 232
		id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
		if (!id)
			continue;

		/* check the client list for the match with this ae_dev type and
		 * un-initialize the figure out client instance
		 */
233 234
		list_for_each_entry(client, &hnae3_client_list, node)
			hnae3_match_n_instantiate(client, ae_dev, false);
235 236

		ae_algo->ops->uninit_ae_dev(ae_dev);
P
Peng Li 已提交
237
		hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0);
238 239 240 241 242 243 244 245 246 247 248
	}

	list_del(&ae_algo->node);
	mutex_unlock(&hnae3_common_lock);
}
EXPORT_SYMBOL(hnae3_unregister_ae_algo);

/* hnae3_register_ae_dev - registers a AE device to hnae3 framework
 * @ae_dev: the AE device
 * NOTE: the duplicated name will not be checked
 */
249
void hnae3_register_ae_dev(struct hnae3_ae_dev *ae_dev)
250 251 252 253
{
	const struct pci_device_id *id;
	struct hnae3_ae_algo *ae_algo;
	struct hnae3_client *client;
254
	int ret = 0;
255

256
	mutex_lock(&hnae3_common_lock);
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275

	list_add_tail(&ae_dev->node, &hnae3_ae_dev_list);

	/* Check if there are matched ae_algo */
	list_for_each_entry(ae_algo, &hnae3_ae_algo_list, node) {
		id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
		if (!id)
			continue;

		ae_dev->ops = ae_algo->ops;

		if (!ae_dev->ops) {
			dev_err(&ae_dev->pdev->dev, "ae_dev ops are null\n");
			goto out_err;
		}

		/* ae_dev init should set flag */
		ret = ae_dev->ops->init_ae_dev(ae_dev);
		if (ret) {
276 277
			dev_err(&ae_dev->pdev->dev,
				"init ae_dev error, ret = %d\n", ret);
278 279 280
			goto out_err;
		}

P
Peng Li 已提交
281
		hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 1);
282 283 284 285 286 287 288
		break;
	}

	/* check the client list for the match with this ae_dev type and
	 * initialize the figure out client instance
	 */
	list_for_each_entry(client, &hnae3_client_list, node) {
289
		ret = hnae3_match_n_instantiate(client, ae_dev, true);
290 291
		if (ret)
			dev_err(&ae_dev->pdev->dev,
292 293
				"match and instantiation failed, ret = %d\n",
				ret);
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312
	}

out_err:
	mutex_unlock(&hnae3_common_lock);
}
EXPORT_SYMBOL(hnae3_register_ae_dev);

/* hnae3_unregister_ae_dev - unregisters a AE device
 * @ae_dev: the AE device to unregister
 */
void hnae3_unregister_ae_dev(struct hnae3_ae_dev *ae_dev)
{
	const struct pci_device_id *id;
	struct hnae3_ae_algo *ae_algo;
	struct hnae3_client *client;

	mutex_lock(&hnae3_common_lock);
	/* Check if there are matched ae_algo */
	list_for_each_entry(ae_algo, &hnae3_ae_algo_list, node) {
P
Peng Li 已提交
313
		if (!hnae3_get_bit(ae_dev->flag, HNAE3_DEV_INITED_B))
314 315
			continue;

316 317 318 319
		id = pci_match_id(ae_algo->pdev_id_table, ae_dev->pdev);
		if (!id)
			continue;

320 321
		list_for_each_entry(client, &hnae3_client_list, node)
			hnae3_match_n_instantiate(client, ae_dev, false);
322 323

		ae_algo->ops->uninit_ae_dev(ae_dev);
P
Peng Li 已提交
324
		hnae3_set_bit(ae_dev->flag, HNAE3_DEV_INITED_B, 0);
325 326 327 328 329 330 331 332 333 334
	}

	list_del(&ae_dev->node);
	mutex_unlock(&hnae3_common_lock);
}
EXPORT_SYMBOL(hnae3_unregister_ae_dev);

MODULE_AUTHOR("Huawei Tech. Co., Ltd.");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("HNAE3(Hisilicon Network Acceleration Engine) Framework");
335
MODULE_VERSION(HNAE3_MOD_VERSION);