brintos

brintos / linux-shallow public Read only

0
0
Text · 21.4 KiB · 23a6eeb Raw
943 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Copyright (c) 2021-2022 NVIDIA Corporation4 *5 * Author: Dipen Patel <dipenp@nvidia.com>6 */7 8#include <linux/kernel.h>9#include <linux/module.h>10#include <linux/err.h>11#include <linux/slab.h>12#include <linux/of.h>13#include <linux/mutex.h>14#include <linux/uaccess.h>15#include <linux/hte.h>16#include <linux/delay.h>17#include <linux/debugfs.h>18#include <linux/device.h>19 20/* Global list of the HTE devices */21static DEFINE_SPINLOCK(hte_lock);22static LIST_HEAD(hte_devices);23 24enum {25	HTE_TS_REGISTERED,26	HTE_TS_REQ,27	HTE_TS_DISABLE,28	HTE_TS_QUEUE_WK,29};30 31/**32 * struct hte_ts_info - Information related to requested timestamp.33 *34 * @xlated_id: Timestamp ID as understood between HTE subsys and HTE provider,35 * See xlate callback API.36 * @flags: Flags holding state information.37 * @hte_cb_flags: Callback related flags.38 * @seq: Timestamp sequence counter.39 * @line_name: HTE allocated line name.40 * @free_attr_name: If set, free the attr name.41 * @cb: A nonsleeping callback function provided by clients.42 * @tcb: A secondary sleeping callback function provided by clients.43 * @dropped_ts: Dropped timestamps.44 * @slock: Spin lock to synchronize between disable/enable,45 * request/release APIs.46 * @cb_work: callback workqueue, used when tcb is specified.47 * @req_mlock: Lock during timestamp request/release APIs.48 * @ts_dbg_root: Root for the debug fs.49 * @gdev: HTE abstract device that this timestamp information belongs to.50 * @cl_data: Client specific data.51 */52struct hte_ts_info {53	u32 xlated_id;54	unsigned long flags;55	unsigned long hte_cb_flags;56	u64 seq;57	char *line_name;58	bool free_attr_name;59	hte_ts_cb_t cb;60	hte_ts_sec_cb_t tcb;61	atomic_t dropped_ts;62	spinlock_t slock;63	struct work_struct cb_work;64	struct mutex req_mlock;65	struct dentry *ts_dbg_root;66	struct hte_device *gdev;67	void *cl_data;68};69 70/**71 * struct hte_device - HTE abstract device72 * @nlines: Number of entities this device supports.73 * @ts_req: Total number of entities requested.74 * @sdev: Device used at various debug prints.75 * @dbg_root: Root directory for debug fs.76 * @list: List node to store hte_device for each provider.77 * @chip: HTE chip providing this HTE device.78 * @owner: helps prevent removal of modules when in use.79 * @ei: Timestamp information.80 */81struct hte_device {82	u32 nlines;83	atomic_t ts_req;84	struct device *sdev;85	struct dentry *dbg_root;86	struct list_head list;87	struct hte_chip *chip;88	struct module *owner;89	struct hte_ts_info ei[] __counted_by(nlines);90};91 92#ifdef CONFIG_DEBUG_FS93 94static struct dentry *hte_root;95 96static int __init hte_subsys_dbgfs_init(void)97{98	/* creates /sys/kernel/debug/hte/ */99	hte_root = debugfs_create_dir("hte", NULL);100 101	return 0;102}103subsys_initcall(hte_subsys_dbgfs_init);104 105static void hte_chip_dbgfs_init(struct hte_device *gdev)106{107	const struct hte_chip *chip = gdev->chip;108	const char *name = chip->name ? chip->name : dev_name(chip->dev);109 110	gdev->dbg_root = debugfs_create_dir(name, hte_root);111 112	debugfs_create_atomic_t("ts_requested", 0444, gdev->dbg_root,113				&gdev->ts_req);114	debugfs_create_u32("total_ts", 0444, gdev->dbg_root,115			   &gdev->nlines);116}117 118static void hte_ts_dbgfs_init(const char *name, struct hte_ts_info *ei)119{120	if (!ei->gdev->dbg_root || !name)121		return;122 123	ei->ts_dbg_root = debugfs_create_dir(name, ei->gdev->dbg_root);124 125	debugfs_create_atomic_t("dropped_timestamps", 0444, ei->ts_dbg_root,126				&ei->dropped_ts);127}128 129#else130 131static void hte_chip_dbgfs_init(struct hte_device *gdev)132{133}134 135static void hte_ts_dbgfs_init(const char *name, struct hte_ts_info *ei)136{137}138 139#endif140 141/**142 * hte_ts_put() - Release and disable timestamp for the given desc.143 *144 * @desc: timestamp descriptor.145 *146 * Context: debugfs_remove_recursive() function call may use sleeping locks,147 *	    not suitable from atomic context.148 * Returns: 0 on success or a negative error code on failure.149 */150int hte_ts_put(struct hte_ts_desc *desc)151{152	int ret = 0;153	unsigned long flag;154	struct hte_device *gdev;155	struct hte_ts_info *ei;156 157	if (!desc)158		return -EINVAL;159 160	ei = desc->hte_data;161 162	if (!ei || !ei->gdev)163		return -EINVAL;164 165	gdev = ei->gdev;166 167	mutex_lock(&ei->req_mlock);168 169	if (unlikely(!test_bit(HTE_TS_REQ, &ei->flags) &&170	    !test_bit(HTE_TS_REGISTERED, &ei->flags))) {171		dev_info(gdev->sdev, "id:%d is not requested\n",172			 desc->attr.line_id);173		ret = -EINVAL;174		goto unlock;175	}176 177	if (unlikely(!test_bit(HTE_TS_REQ, &ei->flags) &&178	    test_bit(HTE_TS_REGISTERED, &ei->flags))) {179		dev_info(gdev->sdev, "id:%d is registered but not requested\n",180			 desc->attr.line_id);181		ret = -EINVAL;182		goto unlock;183	}184 185	if (test_bit(HTE_TS_REQ, &ei->flags) &&186	    !test_bit(HTE_TS_REGISTERED, &ei->flags)) {187		clear_bit(HTE_TS_REQ, &ei->flags);188		desc->hte_data = NULL;189		ret = 0;190		goto mod_put;191	}192 193	ret = gdev->chip->ops->release(gdev->chip, desc, ei->xlated_id);194	if (ret) {195		dev_err(gdev->sdev, "id: %d free failed\n",196			desc->attr.line_id);197		goto unlock;198	}199 200	kfree(ei->line_name);201	if (ei->free_attr_name)202		kfree_const(desc->attr.name);203 204	debugfs_remove_recursive(ei->ts_dbg_root);205 206	spin_lock_irqsave(&ei->slock, flag);207 208	if (test_bit(HTE_TS_QUEUE_WK, &ei->flags)) {209		spin_unlock_irqrestore(&ei->slock, flag);210		flush_work(&ei->cb_work);211		spin_lock_irqsave(&ei->slock, flag);212	}213 214	atomic_dec(&gdev->ts_req);215	atomic_set(&ei->dropped_ts, 0);216 217	ei->seq = 1;218	ei->flags = 0;219	desc->hte_data = NULL;220 221	spin_unlock_irqrestore(&ei->slock, flag);222 223	ei->cb = NULL;224	ei->tcb = NULL;225	ei->cl_data = NULL;226 227mod_put:228	module_put(gdev->owner);229unlock:230	mutex_unlock(&ei->req_mlock);231	dev_dbg(gdev->sdev, "release id: %d\n", desc->attr.line_id);232 233	return ret;234}235EXPORT_SYMBOL_GPL(hte_ts_put);236 237static int hte_ts_dis_en_common(struct hte_ts_desc *desc, bool en)238{239	u32 ts_id;240	struct hte_device *gdev;241	struct hte_ts_info *ei;242	int ret;243	unsigned long flag;244 245	if (!desc)246		return -EINVAL;247 248	ei = desc->hte_data;249 250	if (!ei || !ei->gdev)251		return -EINVAL;252 253	gdev = ei->gdev;254	ts_id = desc->attr.line_id;255 256	mutex_lock(&ei->req_mlock);257 258	if (!test_bit(HTE_TS_REGISTERED, &ei->flags)) {259		dev_dbg(gdev->sdev, "id:%d is not registered", ts_id);260		ret = -EUSERS;261		goto out;262	}263 264	spin_lock_irqsave(&ei->slock, flag);265 266	if (en) {267		if (!test_bit(HTE_TS_DISABLE, &ei->flags)) {268			ret = 0;269			goto out_unlock;270		}271 272		spin_unlock_irqrestore(&ei->slock, flag);273		ret = gdev->chip->ops->enable(gdev->chip, ei->xlated_id);274		if (ret) {275			dev_warn(gdev->sdev, "id: %d enable failed\n",276				 ts_id);277			goto out;278		}279 280		spin_lock_irqsave(&ei->slock, flag);281		clear_bit(HTE_TS_DISABLE, &ei->flags);282	} else {283		if (test_bit(HTE_TS_DISABLE, &ei->flags)) {284			ret = 0;285			goto out_unlock;286		}287 288		spin_unlock_irqrestore(&ei->slock, flag);289		ret = gdev->chip->ops->disable(gdev->chip, ei->xlated_id);290		if (ret) {291			dev_warn(gdev->sdev, "id: %d disable failed\n",292				 ts_id);293			goto out;294		}295 296		spin_lock_irqsave(&ei->slock, flag);297		set_bit(HTE_TS_DISABLE, &ei->flags);298	}299 300out_unlock:301	spin_unlock_irqrestore(&ei->slock, flag);302out:303	mutex_unlock(&ei->req_mlock);304	return ret;305}306 307/**308 * hte_disable_ts() - Disable timestamp on given descriptor.309 *310 * The API does not release any resources associated with desc.311 *312 * @desc: ts descriptor, this is the same as returned by the request API.313 *314 * Context: Holds mutex lock, not suitable from atomic context.315 * Returns: 0 on success or a negative error code on failure.316 */317int hte_disable_ts(struct hte_ts_desc *desc)318{319	return hte_ts_dis_en_common(desc, false);320}321EXPORT_SYMBOL_GPL(hte_disable_ts);322 323/**324 * hte_enable_ts() - Enable timestamp on given descriptor.325 *326 * @desc: ts descriptor, this is the same as returned by the request API.327 *328 * Context: Holds mutex lock, not suitable from atomic context.329 * Returns: 0 on success or a negative error code on failure.330 */331int hte_enable_ts(struct hte_ts_desc *desc)332{333	return hte_ts_dis_en_common(desc, true);334}335EXPORT_SYMBOL_GPL(hte_enable_ts);336 337static void hte_do_cb_work(struct work_struct *w)338{339	unsigned long flag;340	struct hte_ts_info *ei = container_of(w, struct hte_ts_info, cb_work);341 342	if (unlikely(!ei->tcb))343		return;344 345	ei->tcb(ei->cl_data);346 347	spin_lock_irqsave(&ei->slock, flag);348	clear_bit(HTE_TS_QUEUE_WK, &ei->flags);349	spin_unlock_irqrestore(&ei->slock, flag);350}351 352static int __hte_req_ts(struct hte_ts_desc *desc, hte_ts_cb_t cb,353			hte_ts_sec_cb_t tcb, void *data)354{355	int ret;356	struct hte_device *gdev;357	struct hte_ts_info *ei = desc->hte_data;358 359	gdev = ei->gdev;360	/*361	 * There is a chance that multiple consumers requesting same entity,362	 * lock here.363	 */364	mutex_lock(&ei->req_mlock);365 366	if (test_bit(HTE_TS_REGISTERED, &ei->flags) ||367	    !test_bit(HTE_TS_REQ, &ei->flags)) {368		dev_dbg(gdev->chip->dev, "id:%u req failed\n",369			desc->attr.line_id);370		ret = -EUSERS;371		goto unlock;372	}373 374	ei->cb = cb;375	ei->tcb = tcb;376	if (tcb)377		INIT_WORK(&ei->cb_work, hte_do_cb_work);378 379	ret = gdev->chip->ops->request(gdev->chip, desc, ei->xlated_id);380	if (ret < 0) {381		dev_err(gdev->chip->dev, "ts request failed\n");382		goto unlock;383	}384 385	ei->cl_data = data;386	ei->seq = 1;387 388	atomic_inc(&gdev->ts_req);389 390	if (desc->attr.name)391		ei->line_name = NULL;392	else393		ei->line_name = kasprintf(GFP_KERNEL, "ts_%u", desc->attr.line_id);394 395	hte_ts_dbgfs_init(desc->attr.name == NULL ?396			  ei->line_name : desc->attr.name, ei);397	set_bit(HTE_TS_REGISTERED, &ei->flags);398 399	dev_dbg(gdev->chip->dev, "id: %u, xlated id:%u",400		desc->attr.line_id, ei->xlated_id);401 402	ret = 0;403 404unlock:405	mutex_unlock(&ei->req_mlock);406 407	return ret;408}409 410static int hte_bind_ts_info_locked(struct hte_ts_info *ei,411				   struct hte_ts_desc *desc, u32 x_id)412{413	int ret = 0;414 415	mutex_lock(&ei->req_mlock);416 417	if (test_bit(HTE_TS_REQ, &ei->flags)) {418		dev_dbg(ei->gdev->chip->dev, "id:%u is already requested\n",419			desc->attr.line_id);420		ret = -EUSERS;421		goto out;422	}423 424	set_bit(HTE_TS_REQ, &ei->flags);425	desc->hte_data = ei;426	ei->xlated_id = x_id;427 428out:429	mutex_unlock(&ei->req_mlock);430 431	return ret;432}433 434static struct hte_device *of_node_to_htedevice(struct device_node *np)435{436	struct hte_device *gdev;437 438	spin_lock(&hte_lock);439 440	list_for_each_entry(gdev, &hte_devices, list)441		if (gdev->chip && gdev->chip->dev &&442		    device_match_of_node(gdev->chip->dev, np)) {443			spin_unlock(&hte_lock);444			return gdev;445		}446 447	spin_unlock(&hte_lock);448 449	return ERR_PTR(-ENODEV);450}451 452static struct hte_device *hte_find_dev_from_linedata(struct hte_ts_desc *desc)453{454	struct hte_device *gdev;455 456	spin_lock(&hte_lock);457 458	list_for_each_entry(gdev, &hte_devices, list)459		if (gdev->chip && gdev->chip->match_from_linedata) {460			if (!gdev->chip->match_from_linedata(gdev->chip, desc))461				continue;462			spin_unlock(&hte_lock);463			return gdev;464		}465 466	spin_unlock(&hte_lock);467 468	return ERR_PTR(-ENODEV);469}470 471/**472 * of_hte_req_count - Return the number of entities to timestamp.473 *474 * The function returns the total count of the requested entities to timestamp475 * by parsing device tree.476 *477 * @dev: The HTE consumer.478 *479 * Returns: Positive number on success, -ENOENT if no entries,480 * -EINVAL for other errors.481 */482int of_hte_req_count(struct device *dev)483{484	int count;485 486	if (!dev || !dev->of_node)487		return -EINVAL;488 489	count = of_count_phandle_with_args(dev->of_node, "timestamps",490					   "#timestamp-cells");491 492	return count ? count : -ENOENT;493}494EXPORT_SYMBOL_GPL(of_hte_req_count);495 496static inline struct hte_device *hte_get_dev(struct hte_ts_desc *desc)497{498	return hte_find_dev_from_linedata(desc);499}500 501static struct hte_device *hte_of_get_dev(struct device *dev,502					 struct hte_ts_desc *desc,503					 int index,504					 struct of_phandle_args *args,505					 bool *free_name)506{507	int ret;508	struct device_node *np;509	char *temp;510 511	if (!dev->of_node)512		return ERR_PTR(-EINVAL);513 514	np = dev->of_node;515 516	if (!of_property_present(np, "timestamp-names")) {517		/* Let hte core construct it during request time */518		desc->attr.name = NULL;519	} else {520		ret = of_property_read_string_index(np, "timestamp-names",521						    index, &desc->attr.name);522		if (ret) {523			pr_err("can't parse \"timestamp-names\" property\n");524			return ERR_PTR(ret);525		}526		*free_name = false;527		if (desc->attr.name) {528			temp = skip_spaces(desc->attr.name);529			if (!*temp)530				desc->attr.name = NULL;531		}532	}533 534	ret = of_parse_phandle_with_args(np, "timestamps", "#timestamp-cells",535					 index, args);536	if (ret) {537		pr_err("%s(): can't parse \"timestamps\" property\n",538		       __func__);539		return ERR_PTR(ret);540	}541 542	of_node_put(args->np);543 544	return of_node_to_htedevice(args->np);545}546 547/**548 * hte_ts_get() - The function to initialize and obtain HTE desc.549 *550 * The function initializes the consumer provided HTE descriptor. If consumer551 * has device tree node, index is used to parse the line id and other details.552 * The function needs to be called before using any request APIs.553 *554 * @dev: HTE consumer/client device, used in case of parsing device tree node.555 * @desc: Pre-allocated timestamp descriptor.556 * @index: The index will be used as an index to parse line_id from the557 * device tree node if node is present.558 *559 * Context: Holds mutex lock.560 * Returns: Returns 0 on success or negative error code on failure.561 */562int hte_ts_get(struct device *dev, struct hte_ts_desc *desc, int index)563{564	struct hte_device *gdev;565	struct hte_ts_info *ei;566	const struct fwnode_handle *fwnode;567	struct of_phandle_args args;568	u32 xlated_id;569	int ret;570	bool free_name = false;571 572	if (!desc)573		return -EINVAL;574 575	fwnode = dev ? dev_fwnode(dev) : NULL;576 577	if (is_of_node(fwnode))578		gdev = hte_of_get_dev(dev, desc, index, &args, &free_name);579	else580		gdev = hte_get_dev(desc);581 582	if (IS_ERR(gdev)) {583		pr_err("%s() no hte dev found\n", __func__);584		return PTR_ERR(gdev);585	}586 587	if (!try_module_get(gdev->owner))588		return -ENODEV;589 590	if (!gdev->chip) {591		pr_err("%s(): requested id does not have provider\n",592		       __func__);593		ret = -ENODEV;594		goto put;595	}596 597	if (is_of_node(fwnode)) {598		if (!gdev->chip->xlate_of)599			ret = -EINVAL;600		else601			ret = gdev->chip->xlate_of(gdev->chip, &args,602						   desc, &xlated_id);603	} else {604		if (!gdev->chip->xlate_plat)605			ret = -EINVAL;606		else607			ret = gdev->chip->xlate_plat(gdev->chip, desc,608						     &xlated_id);609	}610 611	if (ret < 0)612		goto put;613 614	ei = &gdev->ei[xlated_id];615 616	ret = hte_bind_ts_info_locked(ei, desc, xlated_id);617	if (ret)618		goto put;619 620	ei->free_attr_name = free_name;621 622	return 0;623 624put:625	module_put(gdev->owner);626	return ret;627}628EXPORT_SYMBOL_GPL(hte_ts_get);629 630static void __devm_hte_release_ts(void *res)631{632	hte_ts_put(res);633}634 635/**636 * hte_request_ts_ns() - The API to request and enable hardware timestamp in637 * nanoseconds.638 *639 * The entity is provider specific for example, GPIO lines, signals, buses640 * etc...The API allocates necessary resources and enables the timestamp.641 *642 * @desc: Pre-allocated and initialized timestamp descriptor.643 * @cb: Callback to push the timestamp data to consumer.644 * @tcb: Optional callback. If its provided, subsystem initializes645 * workqueue. It is called when cb returns HTE_RUN_SECOND_CB.646 * @data: Client data, used during cb and tcb callbacks.647 *648 * Context: Holds mutex lock.649 * Returns: Returns 0 on success or negative error code on failure.650 */651int hte_request_ts_ns(struct hte_ts_desc *desc, hte_ts_cb_t cb,652		      hte_ts_sec_cb_t tcb, void *data)653{654	int ret;655	struct hte_ts_info *ei;656 657	if (!desc || !desc->hte_data || !cb)658		return -EINVAL;659 660	ei = desc->hte_data;661	if (!ei || !ei->gdev)662		return -EINVAL;663 664	ret = __hte_req_ts(desc, cb, tcb, data);665	if (ret < 0) {666		dev_err(ei->gdev->chip->dev,667			"failed to request id: %d\n", desc->attr.line_id);668		return ret;669	}670 671	return 0;672}673EXPORT_SYMBOL_GPL(hte_request_ts_ns);674 675/**676 * devm_hte_request_ts_ns() - Resource managed API to request and enable677 * hardware timestamp in nanoseconds.678 *679 * The entity is provider specific for example, GPIO lines, signals, buses680 * etc...The API allocates necessary resources and enables the timestamp. It681 * deallocates and disables automatically when the consumer exits.682 *683 * @dev: HTE consumer/client device.684 * @desc: Pre-allocated and initialized timestamp descriptor.685 * @cb: Callback to push the timestamp data to consumer.686 * @tcb: Optional callback. If its provided, subsystem initializes687 * workqueue. It is called when cb returns HTE_RUN_SECOND_CB.688 * @data: Client data, used during cb and tcb callbacks.689 *690 * Context: Holds mutex lock.691 * Returns: Returns 0 on success or negative error code on failure.692 */693int devm_hte_request_ts_ns(struct device *dev, struct hte_ts_desc *desc,694			   hte_ts_cb_t cb, hte_ts_sec_cb_t tcb,695			   void *data)696{697	int err;698 699	if (!dev)700		return -EINVAL;701 702	err = hte_request_ts_ns(desc, cb, tcb, data);703	if (err)704		return err;705 706	err = devm_add_action_or_reset(dev, __devm_hte_release_ts, desc);707	if (err)708		return err;709 710	return 0;711}712EXPORT_SYMBOL_GPL(devm_hte_request_ts_ns);713 714/**715 * hte_init_line_attr() - Initialize line attributes.716 *717 * Zeroes out line attributes and initializes with provided arguments.718 * The function needs to be called before calling any consumer facing719 * functions.720 *721 * @desc: Pre-allocated timestamp descriptor.722 * @line_id: line id.723 * @edge_flags: edge flags related to line_id.724 * @name: name of the line.725 * @data: line data related to line_id.726 *727 * Context: Any.728 * Returns: 0 on success or negative error code for the failure.729 */730int hte_init_line_attr(struct hte_ts_desc *desc, u32 line_id,731		       unsigned long edge_flags, const char *name, void *data)732{733	if (!desc)734		return -EINVAL;735 736	memset(&desc->attr, 0, sizeof(desc->attr));737 738	desc->attr.edge_flags = edge_flags;739	desc->attr.line_id = line_id;740	desc->attr.line_data = data;741	if (name) {742		name =  kstrdup_const(name, GFP_KERNEL);743		if (!name)744			return -ENOMEM;745	}746 747	desc->attr.name = name;748 749	return 0;750}751EXPORT_SYMBOL_GPL(hte_init_line_attr);752 753/**754 * hte_get_clk_src_info() - Get the clock source information for a ts755 * descriptor.756 *757 * @desc: ts descriptor, same as returned from request API.758 * @ci: The API fills this structure with the clock information data.759 *760 * Context: Any context.761 * Returns: 0 on success else negative error code on failure.762 */763int hte_get_clk_src_info(const struct hte_ts_desc *desc,764			 struct hte_clk_info *ci)765{766	struct hte_chip *chip;767	struct hte_ts_info *ei;768 769	if (!desc || !desc->hte_data || !ci) {770		pr_debug("%s:%d\n", __func__, __LINE__);771		return -EINVAL;772	}773 774	ei = desc->hte_data;775	if (!ei->gdev || !ei->gdev->chip)776		return -EINVAL;777 778	chip = ei->gdev->chip;779	if (!chip->ops->get_clk_src_info)780		return -EOPNOTSUPP;781 782	return chip->ops->get_clk_src_info(chip, ci);783}784EXPORT_SYMBOL_GPL(hte_get_clk_src_info);785 786/**787 * hte_push_ts_ns() - Push timestamp data in nanoseconds.788 *789 * It is used by the provider to push timestamp data.790 *791 * @chip: The HTE chip, used during the registration.792 * @xlated_id: entity id understood by both subsystem and provider, this is793 * obtained from xlate callback during request API.794 * @data: timestamp data.795 *796 * Returns: 0 on success or a negative error code on failure.797 */798int hte_push_ts_ns(const struct hte_chip *chip, u32 xlated_id,799		   struct hte_ts_data *data)800{801	enum hte_return ret;802	int st = 0;803	struct hte_ts_info *ei;804	unsigned long flag;805 806	if (!chip || !data || !chip->gdev)807		return -EINVAL;808 809	if (xlated_id >= chip->nlines)810		return -EINVAL;811 812	ei = &chip->gdev->ei[xlated_id];813 814	spin_lock_irqsave(&ei->slock, flag);815 816	/* timestamp sequence counter */817	data->seq = ei->seq++;818 819	if (!test_bit(HTE_TS_REGISTERED, &ei->flags) ||820	    test_bit(HTE_TS_DISABLE, &ei->flags)) {821		dev_dbg(chip->dev, "Unknown timestamp push\n");822		atomic_inc(&ei->dropped_ts);823		st = -EINVAL;824		goto unlock;825	}826 827	ret = ei->cb(data, ei->cl_data);828	if (ret == HTE_RUN_SECOND_CB && ei->tcb) {829		queue_work(system_unbound_wq, &ei->cb_work);830		set_bit(HTE_TS_QUEUE_WK, &ei->flags);831	}832 833unlock:834	spin_unlock_irqrestore(&ei->slock, flag);835 836	return st;837}838EXPORT_SYMBOL_GPL(hte_push_ts_ns);839 840static int hte_register_chip(struct hte_chip *chip)841{842	struct hte_device *gdev;843	u32 i;844 845	if (!chip || !chip->dev || !chip->dev->of_node)846		return -EINVAL;847 848	if (!chip->ops || !chip->ops->request || !chip->ops->release) {849		dev_err(chip->dev, "Driver needs to provide ops\n");850		return -EINVAL;851	}852 853	gdev = kzalloc(struct_size(gdev, ei, chip->nlines), GFP_KERNEL);854	if (!gdev)855		return -ENOMEM;856 857	gdev->chip = chip;858	chip->gdev = gdev;859	gdev->nlines = chip->nlines;860	gdev->sdev = chip->dev;861 862	for (i = 0; i < chip->nlines; i++) {863		gdev->ei[i].gdev = gdev;864		mutex_init(&gdev->ei[i].req_mlock);865		spin_lock_init(&gdev->ei[i].slock);866	}867 868	if (chip->dev->driver)869		gdev->owner = chip->dev->driver->owner;870	else871		gdev->owner = THIS_MODULE;872 873	of_node_get(chip->dev->of_node);874 875	INIT_LIST_HEAD(&gdev->list);876 877	spin_lock(&hte_lock);878	list_add_tail(&gdev->list, &hte_devices);879	spin_unlock(&hte_lock);880 881	hte_chip_dbgfs_init(gdev);882 883	dev_dbg(chip->dev, "Added hte chip\n");884 885	return 0;886}887 888static int hte_unregister_chip(struct hte_chip *chip)889{890	struct hte_device *gdev;891 892	if (!chip)893		return -EINVAL;894 895	gdev = chip->gdev;896 897	spin_lock(&hte_lock);898	list_del(&gdev->list);899	spin_unlock(&hte_lock);900 901	gdev->chip = NULL;902 903	of_node_put(chip->dev->of_node);904	debugfs_remove_recursive(gdev->dbg_root);905	kfree(gdev);906 907	dev_dbg(chip->dev, "Removed hte chip\n");908 909	return 0;910}911 912static void _hte_devm_unregister_chip(void *chip)913{914	hte_unregister_chip(chip);915}916 917/**918 * devm_hte_register_chip() - Resource managed API to register HTE chip.919 *920 * It is used by the provider to register itself with the HTE subsystem.921 * The unregistration is done automatically when the provider exits.922 *923 * @chip: the HTE chip to add to subsystem.924 *925 * Returns: 0 on success or a negative error code on failure.926 */927int devm_hte_register_chip(struct hte_chip *chip)928{929	int err;930 931	err = hte_register_chip(chip);932	if (err)933		return err;934 935	err = devm_add_action_or_reset(chip->dev, _hte_devm_unregister_chip,936				       chip);937	if (err)938		return err;939 940	return 0;941}942EXPORT_SYMBOL_GPL(devm_hte_register_chip);943