131ab09b4SDipen Patel // SPDX-License-Identifier: GPL-2.0 231ab09b4SDipen Patel /* 331ab09b4SDipen Patel * Copyright (c) 2021-2022 NVIDIA Corporation 431ab09b4SDipen Patel * 531ab09b4SDipen Patel * Author: Dipen Patel <dipenp@nvidia.com> 631ab09b4SDipen Patel */ 731ab09b4SDipen Patel 831ab09b4SDipen Patel #include <linux/kernel.h> 931ab09b4SDipen Patel #include <linux/module.h> 1031ab09b4SDipen Patel #include <linux/err.h> 1131ab09b4SDipen Patel #include <linux/slab.h> 1231ab09b4SDipen Patel #include <linux/of.h> 1331ab09b4SDipen Patel #include <linux/of_device.h> 1431ab09b4SDipen Patel #include <linux/mutex.h> 1531ab09b4SDipen Patel #include <linux/uaccess.h> 1631ab09b4SDipen Patel #include <linux/hte.h> 1731ab09b4SDipen Patel #include <linux/delay.h> 1831ab09b4SDipen Patel #include <linux/debugfs.h> 1931ab09b4SDipen Patel 2031ab09b4SDipen Patel #define HTE_TS_NAME_LEN 10 2131ab09b4SDipen Patel 2231ab09b4SDipen Patel /* Global list of the HTE devices */ 2331ab09b4SDipen Patel static DEFINE_SPINLOCK(hte_lock); 2431ab09b4SDipen Patel static LIST_HEAD(hte_devices); 2531ab09b4SDipen Patel 2631ab09b4SDipen Patel enum { 2731ab09b4SDipen Patel HTE_TS_REGISTERED, 2831ab09b4SDipen Patel HTE_TS_REQ, 2931ab09b4SDipen Patel HTE_TS_DISABLE, 3031ab09b4SDipen Patel HTE_TS_QUEUE_WK, 3131ab09b4SDipen Patel }; 3231ab09b4SDipen Patel 3331ab09b4SDipen Patel /** 3431ab09b4SDipen Patel * struct hte_ts_info - Information related to requested timestamp. 3531ab09b4SDipen Patel * 3631ab09b4SDipen Patel * @xlated_id: Timestamp ID as understood between HTE subsys and HTE provider, 3731ab09b4SDipen Patel * See xlate callback API. 3831ab09b4SDipen Patel * @flags: Flags holding state information. 3931ab09b4SDipen Patel * @hte_cb_flags: Callback related flags. 4031ab09b4SDipen Patel * @seq: Timestamp sequence counter. 4131ab09b4SDipen Patel * @line_name: HTE allocated line name. 4231ab09b4SDipen Patel * @free_attr_name: If set, free the attr name. 4331ab09b4SDipen Patel * @cb: A nonsleeping callback function provided by clients. 4431ab09b4SDipen Patel * @tcb: A secondary sleeping callback function provided by clients. 4531ab09b4SDipen Patel * @dropped_ts: Dropped timestamps. 4631ab09b4SDipen Patel * @slock: Spin lock to synchronize between disable/enable, 4731ab09b4SDipen Patel * request/release APIs. 4831ab09b4SDipen Patel * @cb_work: callback workqueue, used when tcb is specified. 4931ab09b4SDipen Patel * @req_mlock: Lock during timestamp request/release APIs. 5031ab09b4SDipen Patel * @ts_dbg_root: Root for the debug fs. 5131ab09b4SDipen Patel * @gdev: HTE abstract device that this timestamp information belongs to. 5231ab09b4SDipen Patel * @cl_data: Client specific data. 5331ab09b4SDipen Patel */ 5431ab09b4SDipen Patel struct hte_ts_info { 5531ab09b4SDipen Patel u32 xlated_id; 5631ab09b4SDipen Patel unsigned long flags; 5731ab09b4SDipen Patel unsigned long hte_cb_flags; 5831ab09b4SDipen Patel u64 seq; 5931ab09b4SDipen Patel char *line_name; 6031ab09b4SDipen Patel bool free_attr_name; 6131ab09b4SDipen Patel hte_ts_cb_t cb; 6231ab09b4SDipen Patel hte_ts_sec_cb_t tcb; 6331ab09b4SDipen Patel atomic_t dropped_ts; 6431ab09b4SDipen Patel spinlock_t slock; 6531ab09b4SDipen Patel struct work_struct cb_work; 6631ab09b4SDipen Patel struct mutex req_mlock; 6731ab09b4SDipen Patel struct dentry *ts_dbg_root; 6831ab09b4SDipen Patel struct hte_device *gdev; 6931ab09b4SDipen Patel void *cl_data; 7031ab09b4SDipen Patel }; 7131ab09b4SDipen Patel 7231ab09b4SDipen Patel /** 7331ab09b4SDipen Patel * struct hte_device - HTE abstract device 7431ab09b4SDipen Patel * @nlines: Number of entities this device supports. 7531ab09b4SDipen Patel * @ts_req: Total number of entities requested. 7631ab09b4SDipen Patel * @sdev: Device used at various debug prints. 7731ab09b4SDipen Patel * @dbg_root: Root directory for debug fs. 7831ab09b4SDipen Patel * @list: List node to store hte_device for each provider. 7931ab09b4SDipen Patel * @chip: HTE chip providing this HTE device. 8031ab09b4SDipen Patel * @owner: helps prevent removal of modules when in use. 8131ab09b4SDipen Patel * @ei: Timestamp information. 8231ab09b4SDipen Patel */ 8331ab09b4SDipen Patel struct hte_device { 8431ab09b4SDipen Patel u32 nlines; 8531ab09b4SDipen Patel atomic_t ts_req; 8631ab09b4SDipen Patel struct device *sdev; 8731ab09b4SDipen Patel struct dentry *dbg_root; 8831ab09b4SDipen Patel struct list_head list; 8931ab09b4SDipen Patel struct hte_chip *chip; 9031ab09b4SDipen Patel struct module *owner; 9131ab09b4SDipen Patel struct hte_ts_info ei[]; 9231ab09b4SDipen Patel }; 9331ab09b4SDipen Patel 9431ab09b4SDipen Patel #ifdef CONFIG_DEBUG_FS 9531ab09b4SDipen Patel 9631ab09b4SDipen Patel static struct dentry *hte_root; 9731ab09b4SDipen Patel 9831ab09b4SDipen Patel static int __init hte_subsys_dbgfs_init(void) 9931ab09b4SDipen Patel { 10031ab09b4SDipen Patel /* creates /sys/kernel/debug/hte/ */ 10131ab09b4SDipen Patel hte_root = debugfs_create_dir("hte", NULL); 10231ab09b4SDipen Patel 10331ab09b4SDipen Patel return 0; 10431ab09b4SDipen Patel } 10531ab09b4SDipen Patel subsys_initcall(hte_subsys_dbgfs_init); 10631ab09b4SDipen Patel 10731ab09b4SDipen Patel static void hte_chip_dbgfs_init(struct hte_device *gdev) 10831ab09b4SDipen Patel { 10931ab09b4SDipen Patel const struct hte_chip *chip = gdev->chip; 11031ab09b4SDipen Patel const char *name = chip->name ? chip->name : dev_name(chip->dev); 11131ab09b4SDipen Patel 11231ab09b4SDipen Patel gdev->dbg_root = debugfs_create_dir(name, hte_root); 11331ab09b4SDipen Patel 11431ab09b4SDipen Patel debugfs_create_atomic_t("ts_requested", 0444, gdev->dbg_root, 11531ab09b4SDipen Patel &gdev->ts_req); 11631ab09b4SDipen Patel debugfs_create_u32("total_ts", 0444, gdev->dbg_root, 11731ab09b4SDipen Patel &gdev->nlines); 11831ab09b4SDipen Patel } 11931ab09b4SDipen Patel 12031ab09b4SDipen Patel static void hte_ts_dbgfs_init(const char *name, struct hte_ts_info *ei) 12131ab09b4SDipen Patel { 12231ab09b4SDipen Patel if (!ei->gdev->dbg_root || !name) 12331ab09b4SDipen Patel return; 12431ab09b4SDipen Patel 12531ab09b4SDipen Patel ei->ts_dbg_root = debugfs_create_dir(name, ei->gdev->dbg_root); 12631ab09b4SDipen Patel 12731ab09b4SDipen Patel debugfs_create_atomic_t("dropped_timestamps", 0444, ei->ts_dbg_root, 12831ab09b4SDipen Patel &ei->dropped_ts); 12931ab09b4SDipen Patel } 13031ab09b4SDipen Patel 13131ab09b4SDipen Patel #else 13231ab09b4SDipen Patel 13331ab09b4SDipen Patel static void hte_chip_dbgfs_init(struct hte_device *gdev) 13431ab09b4SDipen Patel { 13531ab09b4SDipen Patel } 13631ab09b4SDipen Patel 13731ab09b4SDipen Patel static void hte_ts_dbgfs_init(const char *name, struct hte_ts_info *ei) 13831ab09b4SDipen Patel { 13931ab09b4SDipen Patel } 14031ab09b4SDipen Patel 14131ab09b4SDipen Patel #endif 14231ab09b4SDipen Patel 14331ab09b4SDipen Patel /** 14431ab09b4SDipen Patel * hte_ts_put() - Release and disable timestamp for the given desc. 14531ab09b4SDipen Patel * 14631ab09b4SDipen Patel * @desc: timestamp descriptor. 14731ab09b4SDipen Patel * 14831ab09b4SDipen Patel * Context: debugfs_remove_recursive() function call may use sleeping locks, 14931ab09b4SDipen Patel * not suitable from atomic context. 15031ab09b4SDipen Patel * Returns: 0 on success or a negative error code on failure. 15131ab09b4SDipen Patel */ 15231ab09b4SDipen Patel int hte_ts_put(struct hte_ts_desc *desc) 15331ab09b4SDipen Patel { 15431ab09b4SDipen Patel int ret = 0; 15531ab09b4SDipen Patel unsigned long flag; 15631ab09b4SDipen Patel struct hte_device *gdev; 15731ab09b4SDipen Patel struct hte_ts_info *ei; 15831ab09b4SDipen Patel 15931ab09b4SDipen Patel if (!desc) 16031ab09b4SDipen Patel return -EINVAL; 16131ab09b4SDipen Patel 16231ab09b4SDipen Patel ei = desc->hte_data; 16331ab09b4SDipen Patel 16431ab09b4SDipen Patel if (!ei || !ei->gdev) 16531ab09b4SDipen Patel return -EINVAL; 16631ab09b4SDipen Patel 16731ab09b4SDipen Patel gdev = ei->gdev; 16831ab09b4SDipen Patel 16931ab09b4SDipen Patel mutex_lock(&ei->req_mlock); 17031ab09b4SDipen Patel 17131ab09b4SDipen Patel if (unlikely(!test_bit(HTE_TS_REQ, &ei->flags) && 17231ab09b4SDipen Patel !test_bit(HTE_TS_REGISTERED, &ei->flags))) { 17331ab09b4SDipen Patel dev_info(gdev->sdev, "id:%d is not requested\n", 17431ab09b4SDipen Patel desc->attr.line_id); 17531ab09b4SDipen Patel ret = -EINVAL; 17631ab09b4SDipen Patel goto unlock; 17731ab09b4SDipen Patel } 17831ab09b4SDipen Patel 17931ab09b4SDipen Patel if (unlikely(!test_bit(HTE_TS_REQ, &ei->flags) && 18031ab09b4SDipen Patel test_bit(HTE_TS_REGISTERED, &ei->flags))) { 18131ab09b4SDipen Patel dev_info(gdev->sdev, "id:%d is registered but not requested\n", 18231ab09b4SDipen Patel desc->attr.line_id); 18331ab09b4SDipen Patel ret = -EINVAL; 18431ab09b4SDipen Patel goto unlock; 18531ab09b4SDipen Patel } 18631ab09b4SDipen Patel 18731ab09b4SDipen Patel if (test_bit(HTE_TS_REQ, &ei->flags) && 18831ab09b4SDipen Patel !test_bit(HTE_TS_REGISTERED, &ei->flags)) { 18931ab09b4SDipen Patel clear_bit(HTE_TS_REQ, &ei->flags); 19031ab09b4SDipen Patel desc->hte_data = NULL; 19131ab09b4SDipen Patel ret = 0; 19231ab09b4SDipen Patel goto mod_put; 19331ab09b4SDipen Patel } 19431ab09b4SDipen Patel 19531ab09b4SDipen Patel ret = gdev->chip->ops->release(gdev->chip, desc, ei->xlated_id); 19631ab09b4SDipen Patel if (ret) { 19731ab09b4SDipen Patel dev_err(gdev->sdev, "id: %d free failed\n", 19831ab09b4SDipen Patel desc->attr.line_id); 19931ab09b4SDipen Patel goto unlock; 20031ab09b4SDipen Patel } 20131ab09b4SDipen Patel 20231ab09b4SDipen Patel kfree(ei->line_name); 20331ab09b4SDipen Patel if (ei->free_attr_name) 20431ab09b4SDipen Patel kfree_const(desc->attr.name); 20531ab09b4SDipen Patel 20631ab09b4SDipen Patel debugfs_remove_recursive(ei->ts_dbg_root); 20731ab09b4SDipen Patel 20831ab09b4SDipen Patel spin_lock_irqsave(&ei->slock, flag); 20931ab09b4SDipen Patel 21031ab09b4SDipen Patel if (test_bit(HTE_TS_QUEUE_WK, &ei->flags)) { 21131ab09b4SDipen Patel spin_unlock_irqrestore(&ei->slock, flag); 21231ab09b4SDipen Patel flush_work(&ei->cb_work); 21331ab09b4SDipen Patel spin_lock_irqsave(&ei->slock, flag); 21431ab09b4SDipen Patel } 21531ab09b4SDipen Patel 21631ab09b4SDipen Patel atomic_dec(&gdev->ts_req); 21731ab09b4SDipen Patel atomic_set(&ei->dropped_ts, 0); 21831ab09b4SDipen Patel 21931ab09b4SDipen Patel ei->seq = 1; 22031ab09b4SDipen Patel ei->flags = 0; 22131ab09b4SDipen Patel desc->hte_data = NULL; 22231ab09b4SDipen Patel 22331ab09b4SDipen Patel spin_unlock_irqrestore(&ei->slock, flag); 22431ab09b4SDipen Patel 22531ab09b4SDipen Patel ei->cb = NULL; 22631ab09b4SDipen Patel ei->tcb = NULL; 22731ab09b4SDipen Patel ei->cl_data = NULL; 22831ab09b4SDipen Patel 22931ab09b4SDipen Patel mod_put: 23031ab09b4SDipen Patel module_put(gdev->owner); 23131ab09b4SDipen Patel unlock: 23231ab09b4SDipen Patel mutex_unlock(&ei->req_mlock); 23331ab09b4SDipen Patel dev_dbg(gdev->sdev, "release id: %d\n", desc->attr.line_id); 23431ab09b4SDipen Patel 23531ab09b4SDipen Patel return ret; 23631ab09b4SDipen Patel } 23731ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_ts_put); 23831ab09b4SDipen Patel 23931ab09b4SDipen Patel static int hte_ts_dis_en_common(struct hte_ts_desc *desc, bool en) 24031ab09b4SDipen Patel { 24131ab09b4SDipen Patel u32 ts_id; 24231ab09b4SDipen Patel struct hte_device *gdev; 24331ab09b4SDipen Patel struct hte_ts_info *ei; 24431ab09b4SDipen Patel int ret; 24531ab09b4SDipen Patel unsigned long flag; 24631ab09b4SDipen Patel 24731ab09b4SDipen Patel if (!desc) 24831ab09b4SDipen Patel return -EINVAL; 24931ab09b4SDipen Patel 25031ab09b4SDipen Patel ei = desc->hte_data; 25131ab09b4SDipen Patel 25231ab09b4SDipen Patel if (!ei || !ei->gdev) 25331ab09b4SDipen Patel return -EINVAL; 25431ab09b4SDipen Patel 25531ab09b4SDipen Patel gdev = ei->gdev; 25631ab09b4SDipen Patel ts_id = desc->attr.line_id; 25731ab09b4SDipen Patel 25831ab09b4SDipen Patel mutex_lock(&ei->req_mlock); 25931ab09b4SDipen Patel 26031ab09b4SDipen Patel if (!test_bit(HTE_TS_REGISTERED, &ei->flags)) { 26131ab09b4SDipen Patel dev_dbg(gdev->sdev, "id:%d is not registered", ts_id); 26231ab09b4SDipen Patel ret = -EUSERS; 26331ab09b4SDipen Patel goto out; 26431ab09b4SDipen Patel } 26531ab09b4SDipen Patel 26631ab09b4SDipen Patel spin_lock_irqsave(&ei->slock, flag); 26731ab09b4SDipen Patel 26831ab09b4SDipen Patel if (en) { 26931ab09b4SDipen Patel if (!test_bit(HTE_TS_DISABLE, &ei->flags)) { 27031ab09b4SDipen Patel ret = 0; 27131ab09b4SDipen Patel goto out_unlock; 27231ab09b4SDipen Patel } 27331ab09b4SDipen Patel 27431ab09b4SDipen Patel spin_unlock_irqrestore(&ei->slock, flag); 27531ab09b4SDipen Patel ret = gdev->chip->ops->enable(gdev->chip, ei->xlated_id); 27631ab09b4SDipen Patel if (ret) { 27731ab09b4SDipen Patel dev_warn(gdev->sdev, "id: %d enable failed\n", 27831ab09b4SDipen Patel ts_id); 27931ab09b4SDipen Patel goto out; 28031ab09b4SDipen Patel } 28131ab09b4SDipen Patel 28231ab09b4SDipen Patel spin_lock_irqsave(&ei->slock, flag); 28331ab09b4SDipen Patel clear_bit(HTE_TS_DISABLE, &ei->flags); 28431ab09b4SDipen Patel } else { 28531ab09b4SDipen Patel if (test_bit(HTE_TS_DISABLE, &ei->flags)) { 28631ab09b4SDipen Patel ret = 0; 28731ab09b4SDipen Patel goto out_unlock; 28831ab09b4SDipen Patel } 28931ab09b4SDipen Patel 29031ab09b4SDipen Patel spin_unlock_irqrestore(&ei->slock, flag); 29131ab09b4SDipen Patel ret = gdev->chip->ops->disable(gdev->chip, ei->xlated_id); 29231ab09b4SDipen Patel if (ret) { 29331ab09b4SDipen Patel dev_warn(gdev->sdev, "id: %d disable failed\n", 29431ab09b4SDipen Patel ts_id); 29531ab09b4SDipen Patel goto out; 29631ab09b4SDipen Patel } 29731ab09b4SDipen Patel 29831ab09b4SDipen Patel spin_lock_irqsave(&ei->slock, flag); 29931ab09b4SDipen Patel set_bit(HTE_TS_DISABLE, &ei->flags); 30031ab09b4SDipen Patel } 30131ab09b4SDipen Patel 30231ab09b4SDipen Patel out_unlock: 30331ab09b4SDipen Patel spin_unlock_irqrestore(&ei->slock, flag); 30431ab09b4SDipen Patel out: 30531ab09b4SDipen Patel mutex_unlock(&ei->req_mlock); 30631ab09b4SDipen Patel return ret; 30731ab09b4SDipen Patel } 30831ab09b4SDipen Patel 30931ab09b4SDipen Patel /** 31031ab09b4SDipen Patel * hte_disable_ts() - Disable timestamp on given descriptor. 31131ab09b4SDipen Patel * 31231ab09b4SDipen Patel * The API does not release any resources associated with desc. 31331ab09b4SDipen Patel * 31431ab09b4SDipen Patel * @desc: ts descriptor, this is the same as returned by the request API. 31531ab09b4SDipen Patel * 31631ab09b4SDipen Patel * Context: Holds mutex lock, not suitable from atomic context. 31731ab09b4SDipen Patel * Returns: 0 on success or a negative error code on failure. 31831ab09b4SDipen Patel */ 31931ab09b4SDipen Patel int hte_disable_ts(struct hte_ts_desc *desc) 32031ab09b4SDipen Patel { 32131ab09b4SDipen Patel return hte_ts_dis_en_common(desc, false); 32231ab09b4SDipen Patel } 32331ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_disable_ts); 32431ab09b4SDipen Patel 32531ab09b4SDipen Patel /** 32631ab09b4SDipen Patel * hte_enable_ts() - Enable timestamp on given descriptor. 32731ab09b4SDipen Patel * 32831ab09b4SDipen Patel * @desc: ts descriptor, this is the same as returned by the request API. 32931ab09b4SDipen Patel * 33031ab09b4SDipen Patel * Context: Holds mutex lock, not suitable from atomic context. 33131ab09b4SDipen Patel * Returns: 0 on success or a negative error code on failure. 33231ab09b4SDipen Patel */ 33331ab09b4SDipen Patel int hte_enable_ts(struct hte_ts_desc *desc) 33431ab09b4SDipen Patel { 33531ab09b4SDipen Patel return hte_ts_dis_en_common(desc, true); 33631ab09b4SDipen Patel } 33731ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_enable_ts); 33831ab09b4SDipen Patel 33931ab09b4SDipen Patel static void hte_do_cb_work(struct work_struct *w) 34031ab09b4SDipen Patel { 34131ab09b4SDipen Patel unsigned long flag; 34231ab09b4SDipen Patel struct hte_ts_info *ei = container_of(w, struct hte_ts_info, cb_work); 34331ab09b4SDipen Patel 34431ab09b4SDipen Patel if (unlikely(!ei->tcb)) 34531ab09b4SDipen Patel return; 34631ab09b4SDipen Patel 34731ab09b4SDipen Patel ei->tcb(ei->cl_data); 34831ab09b4SDipen Patel 34931ab09b4SDipen Patel spin_lock_irqsave(&ei->slock, flag); 35031ab09b4SDipen Patel clear_bit(HTE_TS_QUEUE_WK, &ei->flags); 35131ab09b4SDipen Patel spin_unlock_irqrestore(&ei->slock, flag); 35231ab09b4SDipen Patel } 35331ab09b4SDipen Patel 35431ab09b4SDipen Patel static int __hte_req_ts(struct hte_ts_desc *desc, hte_ts_cb_t cb, 35531ab09b4SDipen Patel hte_ts_sec_cb_t tcb, void *data) 35631ab09b4SDipen Patel { 35731ab09b4SDipen Patel int ret; 35831ab09b4SDipen Patel struct hte_device *gdev; 35931ab09b4SDipen Patel struct hte_ts_info *ei = desc->hte_data; 36031ab09b4SDipen Patel 36131ab09b4SDipen Patel gdev = ei->gdev; 36231ab09b4SDipen Patel /* 36331ab09b4SDipen Patel * There is a chance that multiple consumers requesting same entity, 36431ab09b4SDipen Patel * lock here. 36531ab09b4SDipen Patel */ 36631ab09b4SDipen Patel mutex_lock(&ei->req_mlock); 36731ab09b4SDipen Patel 36831ab09b4SDipen Patel if (test_bit(HTE_TS_REGISTERED, &ei->flags) || 36931ab09b4SDipen Patel !test_bit(HTE_TS_REQ, &ei->flags)) { 37031ab09b4SDipen Patel dev_dbg(gdev->chip->dev, "id:%u req failed\n", 37131ab09b4SDipen Patel desc->attr.line_id); 37231ab09b4SDipen Patel ret = -EUSERS; 37331ab09b4SDipen Patel goto unlock; 37431ab09b4SDipen Patel } 37531ab09b4SDipen Patel 37631ab09b4SDipen Patel ei->cb = cb; 37731ab09b4SDipen Patel ei->tcb = tcb; 37831ab09b4SDipen Patel if (tcb) 37931ab09b4SDipen Patel INIT_WORK(&ei->cb_work, hte_do_cb_work); 38031ab09b4SDipen Patel 38131ab09b4SDipen Patel ret = gdev->chip->ops->request(gdev->chip, desc, ei->xlated_id); 38231ab09b4SDipen Patel if (ret < 0) { 38331ab09b4SDipen Patel dev_err(gdev->chip->dev, "ts request failed\n"); 38431ab09b4SDipen Patel goto unlock; 38531ab09b4SDipen Patel } 38631ab09b4SDipen Patel 38731ab09b4SDipen Patel ei->cl_data = data; 38831ab09b4SDipen Patel ei->seq = 1; 38931ab09b4SDipen Patel 39031ab09b4SDipen Patel atomic_inc(&gdev->ts_req); 39131ab09b4SDipen Patel 39231ab09b4SDipen Patel ei->line_name = NULL; 39331ab09b4SDipen Patel if (!desc->attr.name) { 39431ab09b4SDipen Patel ei->line_name = kzalloc(HTE_TS_NAME_LEN, GFP_KERNEL); 39531ab09b4SDipen Patel if (ei->line_name) 39631ab09b4SDipen Patel scnprintf(ei->line_name, HTE_TS_NAME_LEN, "ts_%u", 39731ab09b4SDipen Patel desc->attr.line_id); 39831ab09b4SDipen Patel } 39931ab09b4SDipen Patel 40031ab09b4SDipen Patel hte_ts_dbgfs_init(desc->attr.name == NULL ? 40131ab09b4SDipen Patel ei->line_name : desc->attr.name, ei); 40231ab09b4SDipen Patel set_bit(HTE_TS_REGISTERED, &ei->flags); 40331ab09b4SDipen Patel 40431ab09b4SDipen Patel dev_dbg(gdev->chip->dev, "id: %u, xlated id:%u", 40531ab09b4SDipen Patel desc->attr.line_id, ei->xlated_id); 40631ab09b4SDipen Patel 40731ab09b4SDipen Patel ret = 0; 40831ab09b4SDipen Patel 40931ab09b4SDipen Patel unlock: 41031ab09b4SDipen Patel mutex_unlock(&ei->req_mlock); 41131ab09b4SDipen Patel 41231ab09b4SDipen Patel return ret; 41331ab09b4SDipen Patel } 41431ab09b4SDipen Patel 41531ab09b4SDipen Patel static int hte_bind_ts_info_locked(struct hte_ts_info *ei, 41631ab09b4SDipen Patel struct hte_ts_desc *desc, u32 x_id) 41731ab09b4SDipen Patel { 41831ab09b4SDipen Patel int ret = 0; 41931ab09b4SDipen Patel 42031ab09b4SDipen Patel mutex_lock(&ei->req_mlock); 42131ab09b4SDipen Patel 42231ab09b4SDipen Patel if (test_bit(HTE_TS_REQ, &ei->flags)) { 42331ab09b4SDipen Patel dev_dbg(ei->gdev->chip->dev, "id:%u is already requested\n", 42431ab09b4SDipen Patel desc->attr.line_id); 42531ab09b4SDipen Patel ret = -EUSERS; 42631ab09b4SDipen Patel goto out; 42731ab09b4SDipen Patel } 42831ab09b4SDipen Patel 42931ab09b4SDipen Patel set_bit(HTE_TS_REQ, &ei->flags); 43031ab09b4SDipen Patel desc->hte_data = ei; 43131ab09b4SDipen Patel ei->xlated_id = x_id; 43231ab09b4SDipen Patel 43331ab09b4SDipen Patel out: 43431ab09b4SDipen Patel mutex_unlock(&ei->req_mlock); 43531ab09b4SDipen Patel 43631ab09b4SDipen Patel return ret; 43731ab09b4SDipen Patel } 43831ab09b4SDipen Patel 43931ab09b4SDipen Patel static struct hte_device *of_node_to_htedevice(struct device_node *np) 44031ab09b4SDipen Patel { 44131ab09b4SDipen Patel struct hte_device *gdev; 44231ab09b4SDipen Patel 44331ab09b4SDipen Patel spin_lock(&hte_lock); 44431ab09b4SDipen Patel 44531ab09b4SDipen Patel list_for_each_entry(gdev, &hte_devices, list) 44631ab09b4SDipen Patel if (gdev->chip && gdev->chip->dev && 44731ab09b4SDipen Patel gdev->chip->dev->of_node == np) { 44831ab09b4SDipen Patel spin_unlock(&hte_lock); 44931ab09b4SDipen Patel return gdev; 45031ab09b4SDipen Patel } 45131ab09b4SDipen Patel 45231ab09b4SDipen Patel spin_unlock(&hte_lock); 45331ab09b4SDipen Patel 45431ab09b4SDipen Patel return ERR_PTR(-ENODEV); 45531ab09b4SDipen Patel } 45631ab09b4SDipen Patel 45731ab09b4SDipen Patel static struct hte_device *hte_find_dev_from_linedata(struct hte_ts_desc *desc) 45831ab09b4SDipen Patel { 45931ab09b4SDipen Patel struct hte_device *gdev; 46031ab09b4SDipen Patel 46131ab09b4SDipen Patel spin_lock(&hte_lock); 46231ab09b4SDipen Patel 46331ab09b4SDipen Patel list_for_each_entry(gdev, &hte_devices, list) 46431ab09b4SDipen Patel if (gdev->chip && gdev->chip->match_from_linedata) { 46531ab09b4SDipen Patel if (!gdev->chip->match_from_linedata(gdev->chip, desc)) 46631ab09b4SDipen Patel continue; 46731ab09b4SDipen Patel spin_unlock(&hte_lock); 46831ab09b4SDipen Patel return gdev; 46931ab09b4SDipen Patel } 47031ab09b4SDipen Patel 47131ab09b4SDipen Patel spin_unlock(&hte_lock); 47231ab09b4SDipen Patel 47331ab09b4SDipen Patel return ERR_PTR(-ENODEV); 47431ab09b4SDipen Patel } 47531ab09b4SDipen Patel 47631ab09b4SDipen Patel /** 47731ab09b4SDipen Patel * of_hte_req_count - Return the number of entities to timestamp. 47831ab09b4SDipen Patel * 47931ab09b4SDipen Patel * The function returns the total count of the requested entities to timestamp 48031ab09b4SDipen Patel * by parsing device tree. 48131ab09b4SDipen Patel * 48231ab09b4SDipen Patel * @dev: The HTE consumer. 48331ab09b4SDipen Patel * 48431ab09b4SDipen Patel * Returns: Positive number on success, -ENOENT if no entries, 48531ab09b4SDipen Patel * -EINVAL for other errors. 48631ab09b4SDipen Patel */ 48731ab09b4SDipen Patel int of_hte_req_count(struct device *dev) 48831ab09b4SDipen Patel { 48931ab09b4SDipen Patel int count; 49031ab09b4SDipen Patel 49131ab09b4SDipen Patel if (!dev || !dev->of_node) 49231ab09b4SDipen Patel return -EINVAL; 49331ab09b4SDipen Patel 49431ab09b4SDipen Patel count = of_count_phandle_with_args(dev->of_node, "timestamps", 49531ab09b4SDipen Patel "#timestamp-cells"); 49631ab09b4SDipen Patel 49731ab09b4SDipen Patel return count ? count : -ENOENT; 49831ab09b4SDipen Patel } 49931ab09b4SDipen Patel EXPORT_SYMBOL_GPL(of_hte_req_count); 50031ab09b4SDipen Patel 50131ab09b4SDipen Patel static inline struct hte_device *hte_get_dev(struct hte_ts_desc *desc) 50231ab09b4SDipen Patel { 50331ab09b4SDipen Patel return hte_find_dev_from_linedata(desc); 50431ab09b4SDipen Patel } 50531ab09b4SDipen Patel 50631ab09b4SDipen Patel static struct hte_device *hte_of_get_dev(struct device *dev, 50731ab09b4SDipen Patel struct hte_ts_desc *desc, 50831ab09b4SDipen Patel int index, 50931ab09b4SDipen Patel struct of_phandle_args *args, 51031ab09b4SDipen Patel bool *free_name) 51131ab09b4SDipen Patel { 51231ab09b4SDipen Patel int ret; 51331ab09b4SDipen Patel struct device_node *np; 51431ab09b4SDipen Patel char *temp; 51531ab09b4SDipen Patel 51631ab09b4SDipen Patel if (!dev->of_node) 51731ab09b4SDipen Patel return ERR_PTR(-EINVAL); 51831ab09b4SDipen Patel 51931ab09b4SDipen Patel np = dev->of_node; 52031ab09b4SDipen Patel 521*902dea62SRob Herring if (!of_property_present(np, "timestamp-names")) { 52231ab09b4SDipen Patel /* Let hte core construct it during request time */ 52331ab09b4SDipen Patel desc->attr.name = NULL; 52431ab09b4SDipen Patel } else { 52531ab09b4SDipen Patel ret = of_property_read_string_index(np, "timestamp-names", 52631ab09b4SDipen Patel index, &desc->attr.name); 52731ab09b4SDipen Patel if (ret) { 52831ab09b4SDipen Patel pr_err("can't parse \"timestamp-names\" property\n"); 52931ab09b4SDipen Patel return ERR_PTR(ret); 53031ab09b4SDipen Patel } 53131ab09b4SDipen Patel *free_name = false; 53231ab09b4SDipen Patel if (desc->attr.name) { 53331ab09b4SDipen Patel temp = skip_spaces(desc->attr.name); 53431ab09b4SDipen Patel if (!*temp) 53531ab09b4SDipen Patel desc->attr.name = NULL; 53631ab09b4SDipen Patel } 53731ab09b4SDipen Patel } 53831ab09b4SDipen Patel 53931ab09b4SDipen Patel ret = of_parse_phandle_with_args(np, "timestamps", "#timestamp-cells", 54031ab09b4SDipen Patel index, args); 54131ab09b4SDipen Patel if (ret) { 54231ab09b4SDipen Patel pr_err("%s(): can't parse \"timestamps\" property\n", 54331ab09b4SDipen Patel __func__); 54431ab09b4SDipen Patel return ERR_PTR(ret); 54531ab09b4SDipen Patel } 54631ab09b4SDipen Patel 54731ab09b4SDipen Patel of_node_put(args->np); 54831ab09b4SDipen Patel 54931ab09b4SDipen Patel return of_node_to_htedevice(args->np); 55031ab09b4SDipen Patel } 55131ab09b4SDipen Patel 55231ab09b4SDipen Patel /** 55331ab09b4SDipen Patel * hte_ts_get() - The function to initialize and obtain HTE desc. 55431ab09b4SDipen Patel * 55531ab09b4SDipen Patel * The function initializes the consumer provided HTE descriptor. If consumer 55631ab09b4SDipen Patel * has device tree node, index is used to parse the line id and other details. 55731ab09b4SDipen Patel * The function needs to be called before using any request APIs. 55831ab09b4SDipen Patel * 55931ab09b4SDipen Patel * @dev: HTE consumer/client device, used in case of parsing device tree node. 56031ab09b4SDipen Patel * @desc: Pre-allocated timestamp descriptor. 56131ab09b4SDipen Patel * @index: The index will be used as an index to parse line_id from the 56231ab09b4SDipen Patel * device tree node if node is present. 56331ab09b4SDipen Patel * 56431ab09b4SDipen Patel * Context: Holds mutex lock. 56531ab09b4SDipen Patel * Returns: Returns 0 on success or negative error code on failure. 56631ab09b4SDipen Patel */ 56731ab09b4SDipen Patel int hte_ts_get(struct device *dev, struct hte_ts_desc *desc, int index) 56831ab09b4SDipen Patel { 56931ab09b4SDipen Patel struct hte_device *gdev; 57031ab09b4SDipen Patel struct hte_ts_info *ei; 57131ab09b4SDipen Patel const struct fwnode_handle *fwnode; 57231ab09b4SDipen Patel struct of_phandle_args args; 57331ab09b4SDipen Patel u32 xlated_id; 57431ab09b4SDipen Patel int ret; 575348b10b0SDan Carpenter bool free_name = false; 57631ab09b4SDipen Patel 57731ab09b4SDipen Patel if (!desc) 57831ab09b4SDipen Patel return -EINVAL; 57931ab09b4SDipen Patel 58031ab09b4SDipen Patel fwnode = dev ? dev_fwnode(dev) : NULL; 58131ab09b4SDipen Patel 58231ab09b4SDipen Patel if (is_of_node(fwnode)) 58331ab09b4SDipen Patel gdev = hte_of_get_dev(dev, desc, index, &args, &free_name); 58431ab09b4SDipen Patel else 58531ab09b4SDipen Patel gdev = hte_get_dev(desc); 58631ab09b4SDipen Patel 58731ab09b4SDipen Patel if (IS_ERR(gdev)) { 58831ab09b4SDipen Patel pr_err("%s() no hte dev found\n", __func__); 58931ab09b4SDipen Patel return PTR_ERR(gdev); 59031ab09b4SDipen Patel } 59131ab09b4SDipen Patel 59231ab09b4SDipen Patel if (!try_module_get(gdev->owner)) 59331ab09b4SDipen Patel return -ENODEV; 59431ab09b4SDipen Patel 59531ab09b4SDipen Patel if (!gdev->chip) { 59631ab09b4SDipen Patel pr_err("%s(): requested id does not have provider\n", 59731ab09b4SDipen Patel __func__); 59831ab09b4SDipen Patel ret = -ENODEV; 59931ab09b4SDipen Patel goto put; 60031ab09b4SDipen Patel } 60131ab09b4SDipen Patel 60231ab09b4SDipen Patel if (is_of_node(fwnode)) { 60331ab09b4SDipen Patel if (!gdev->chip->xlate_of) 60431ab09b4SDipen Patel ret = -EINVAL; 60531ab09b4SDipen Patel else 60631ab09b4SDipen Patel ret = gdev->chip->xlate_of(gdev->chip, &args, 60731ab09b4SDipen Patel desc, &xlated_id); 60831ab09b4SDipen Patel } else { 60931ab09b4SDipen Patel if (!gdev->chip->xlate_plat) 61031ab09b4SDipen Patel ret = -EINVAL; 61131ab09b4SDipen Patel else 61231ab09b4SDipen Patel ret = gdev->chip->xlate_plat(gdev->chip, desc, 61331ab09b4SDipen Patel &xlated_id); 61431ab09b4SDipen Patel } 61531ab09b4SDipen Patel 61631ab09b4SDipen Patel if (ret < 0) 61731ab09b4SDipen Patel goto put; 61831ab09b4SDipen Patel 61931ab09b4SDipen Patel ei = &gdev->ei[xlated_id]; 62031ab09b4SDipen Patel 62131ab09b4SDipen Patel ret = hte_bind_ts_info_locked(ei, desc, xlated_id); 62231ab09b4SDipen Patel if (ret) 62331ab09b4SDipen Patel goto put; 62431ab09b4SDipen Patel 62531ab09b4SDipen Patel ei->free_attr_name = free_name; 62631ab09b4SDipen Patel 62731ab09b4SDipen Patel return 0; 62831ab09b4SDipen Patel 62931ab09b4SDipen Patel put: 63031ab09b4SDipen Patel module_put(gdev->owner); 63131ab09b4SDipen Patel return ret; 63231ab09b4SDipen Patel } 63331ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_ts_get); 63431ab09b4SDipen Patel 63531ab09b4SDipen Patel static void __devm_hte_release_ts(void *res) 63631ab09b4SDipen Patel { 63731ab09b4SDipen Patel hte_ts_put(res); 63831ab09b4SDipen Patel } 63931ab09b4SDipen Patel 64031ab09b4SDipen Patel /** 64131ab09b4SDipen Patel * hte_request_ts_ns() - The API to request and enable hardware timestamp in 64231ab09b4SDipen Patel * nanoseconds. 64331ab09b4SDipen Patel * 64431ab09b4SDipen Patel * The entity is provider specific for example, GPIO lines, signals, buses 64531ab09b4SDipen Patel * etc...The API allocates necessary resources and enables the timestamp. 64631ab09b4SDipen Patel * 64731ab09b4SDipen Patel * @desc: Pre-allocated and initialized timestamp descriptor. 64831ab09b4SDipen Patel * @cb: Callback to push the timestamp data to consumer. 64931ab09b4SDipen Patel * @tcb: Optional callback. If its provided, subsystem initializes 65031ab09b4SDipen Patel * workqueue. It is called when cb returns HTE_RUN_SECOND_CB. 65131ab09b4SDipen Patel * @data: Client data, used during cb and tcb callbacks. 65231ab09b4SDipen Patel * 65331ab09b4SDipen Patel * Context: Holds mutex lock. 65431ab09b4SDipen Patel * Returns: Returns 0 on success or negative error code on failure. 65531ab09b4SDipen Patel */ 65631ab09b4SDipen Patel int hte_request_ts_ns(struct hte_ts_desc *desc, hte_ts_cb_t cb, 65731ab09b4SDipen Patel hte_ts_sec_cb_t tcb, void *data) 65831ab09b4SDipen Patel { 65931ab09b4SDipen Patel int ret; 66031ab09b4SDipen Patel struct hte_ts_info *ei; 66131ab09b4SDipen Patel 66231ab09b4SDipen Patel if (!desc || !desc->hte_data || !cb) 66331ab09b4SDipen Patel return -EINVAL; 66431ab09b4SDipen Patel 66531ab09b4SDipen Patel ei = desc->hte_data; 66631ab09b4SDipen Patel if (!ei || !ei->gdev) 66731ab09b4SDipen Patel return -EINVAL; 66831ab09b4SDipen Patel 66931ab09b4SDipen Patel ret = __hte_req_ts(desc, cb, tcb, data); 67031ab09b4SDipen Patel if (ret < 0) { 67131ab09b4SDipen Patel dev_err(ei->gdev->chip->dev, 67231ab09b4SDipen Patel "failed to request id: %d\n", desc->attr.line_id); 67331ab09b4SDipen Patel return ret; 67431ab09b4SDipen Patel } 67531ab09b4SDipen Patel 67631ab09b4SDipen Patel return 0; 67731ab09b4SDipen Patel } 67831ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_request_ts_ns); 67931ab09b4SDipen Patel 68031ab09b4SDipen Patel /** 68131ab09b4SDipen Patel * devm_hte_request_ts_ns() - Resource managed API to request and enable 68231ab09b4SDipen Patel * hardware timestamp in nanoseconds. 68331ab09b4SDipen Patel * 68431ab09b4SDipen Patel * The entity is provider specific for example, GPIO lines, signals, buses 68531ab09b4SDipen Patel * etc...The API allocates necessary resources and enables the timestamp. It 68631ab09b4SDipen Patel * deallocates and disables automatically when the consumer exits. 68731ab09b4SDipen Patel * 68831ab09b4SDipen Patel * @dev: HTE consumer/client device. 68931ab09b4SDipen Patel * @desc: Pre-allocated and initialized timestamp descriptor. 69031ab09b4SDipen Patel * @cb: Callback to push the timestamp data to consumer. 69131ab09b4SDipen Patel * @tcb: Optional callback. If its provided, subsystem initializes 69231ab09b4SDipen Patel * workqueue. It is called when cb returns HTE_RUN_SECOND_CB. 69331ab09b4SDipen Patel * @data: Client data, used during cb and tcb callbacks. 69431ab09b4SDipen Patel * 69531ab09b4SDipen Patel * Context: Holds mutex lock. 69631ab09b4SDipen Patel * Returns: Returns 0 on success or negative error code on failure. 69731ab09b4SDipen Patel */ 69831ab09b4SDipen Patel int devm_hte_request_ts_ns(struct device *dev, struct hte_ts_desc *desc, 69931ab09b4SDipen Patel hte_ts_cb_t cb, hte_ts_sec_cb_t tcb, 70031ab09b4SDipen Patel void *data) 70131ab09b4SDipen Patel { 70231ab09b4SDipen Patel int err; 70331ab09b4SDipen Patel 70431ab09b4SDipen Patel if (!dev) 70531ab09b4SDipen Patel return -EINVAL; 70631ab09b4SDipen Patel 70731ab09b4SDipen Patel err = hte_request_ts_ns(desc, cb, tcb, data); 70831ab09b4SDipen Patel if (err) 70931ab09b4SDipen Patel return err; 71031ab09b4SDipen Patel 71131ab09b4SDipen Patel err = devm_add_action_or_reset(dev, __devm_hte_release_ts, desc); 71231ab09b4SDipen Patel if (err) 71331ab09b4SDipen Patel return err; 71431ab09b4SDipen Patel 71531ab09b4SDipen Patel return 0; 71631ab09b4SDipen Patel } 71731ab09b4SDipen Patel EXPORT_SYMBOL_GPL(devm_hte_request_ts_ns); 71831ab09b4SDipen Patel 71931ab09b4SDipen Patel /** 72031ab09b4SDipen Patel * hte_init_line_attr() - Initialize line attributes. 72131ab09b4SDipen Patel * 72231ab09b4SDipen Patel * Zeroes out line attributes and initializes with provided arguments. 72331ab09b4SDipen Patel * The function needs to be called before calling any consumer facing 72431ab09b4SDipen Patel * functions. 72531ab09b4SDipen Patel * 72631ab09b4SDipen Patel * @desc: Pre-allocated timestamp descriptor. 72731ab09b4SDipen Patel * @line_id: line id. 72831ab09b4SDipen Patel * @edge_flags: edge flags related to line_id. 72931ab09b4SDipen Patel * @name: name of the line. 73031ab09b4SDipen Patel * @data: line data related to line_id. 73131ab09b4SDipen Patel * 73231ab09b4SDipen Patel * Context: Any. 73331ab09b4SDipen Patel * Returns: 0 on success or negative error code for the failure. 73431ab09b4SDipen Patel */ 73531ab09b4SDipen Patel int hte_init_line_attr(struct hte_ts_desc *desc, u32 line_id, 73631ab09b4SDipen Patel unsigned long edge_flags, const char *name, void *data) 73731ab09b4SDipen Patel { 73831ab09b4SDipen Patel if (!desc) 73931ab09b4SDipen Patel return -EINVAL; 74031ab09b4SDipen Patel 74131ab09b4SDipen Patel memset(&desc->attr, 0, sizeof(desc->attr)); 74231ab09b4SDipen Patel 74331ab09b4SDipen Patel desc->attr.edge_flags = edge_flags; 74431ab09b4SDipen Patel desc->attr.line_id = line_id; 74531ab09b4SDipen Patel desc->attr.line_data = data; 74631ab09b4SDipen Patel if (name) { 74731ab09b4SDipen Patel name = kstrdup_const(name, GFP_KERNEL); 74831ab09b4SDipen Patel if (!name) 74931ab09b4SDipen Patel return -ENOMEM; 75031ab09b4SDipen Patel } 75131ab09b4SDipen Patel 75231ab09b4SDipen Patel desc->attr.name = name; 75331ab09b4SDipen Patel 75431ab09b4SDipen Patel return 0; 75531ab09b4SDipen Patel } 75631ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_init_line_attr); 75731ab09b4SDipen Patel 75831ab09b4SDipen Patel /** 75931ab09b4SDipen Patel * hte_get_clk_src_info() - Get the clock source information for a ts 76031ab09b4SDipen Patel * descriptor. 76131ab09b4SDipen Patel * 76231ab09b4SDipen Patel * @desc: ts descriptor, same as returned from request API. 76331ab09b4SDipen Patel * @ci: The API fills this structure with the clock information data. 76431ab09b4SDipen Patel * 76531ab09b4SDipen Patel * Context: Any context. 76631ab09b4SDipen Patel * Returns: 0 on success else negative error code on failure. 76731ab09b4SDipen Patel */ 76831ab09b4SDipen Patel int hte_get_clk_src_info(const struct hte_ts_desc *desc, 76931ab09b4SDipen Patel struct hte_clk_info *ci) 77031ab09b4SDipen Patel { 77131ab09b4SDipen Patel struct hte_chip *chip; 77231ab09b4SDipen Patel struct hte_ts_info *ei; 77331ab09b4SDipen Patel 77431ab09b4SDipen Patel if (!desc || !desc->hte_data || !ci) { 77531ab09b4SDipen Patel pr_debug("%s:%d\n", __func__, __LINE__); 77631ab09b4SDipen Patel return -EINVAL; 77731ab09b4SDipen Patel } 77831ab09b4SDipen Patel 77931ab09b4SDipen Patel ei = desc->hte_data; 78031ab09b4SDipen Patel if (!ei->gdev || !ei->gdev->chip) 78131ab09b4SDipen Patel return -EINVAL; 78231ab09b4SDipen Patel 78331ab09b4SDipen Patel chip = ei->gdev->chip; 78431ab09b4SDipen Patel if (!chip->ops->get_clk_src_info) 78531ab09b4SDipen Patel return -EOPNOTSUPP; 78631ab09b4SDipen Patel 78731ab09b4SDipen Patel return chip->ops->get_clk_src_info(chip, ci); 78831ab09b4SDipen Patel } 78931ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_get_clk_src_info); 79031ab09b4SDipen Patel 79131ab09b4SDipen Patel /** 79231ab09b4SDipen Patel * hte_push_ts_ns() - Push timestamp data in nanoseconds. 79331ab09b4SDipen Patel * 79431ab09b4SDipen Patel * It is used by the provider to push timestamp data. 79531ab09b4SDipen Patel * 79631ab09b4SDipen Patel * @chip: The HTE chip, used during the registration. 79731ab09b4SDipen Patel * @xlated_id: entity id understood by both subsystem and provider, this is 79831ab09b4SDipen Patel * obtained from xlate callback during request API. 79931ab09b4SDipen Patel * @data: timestamp data. 80031ab09b4SDipen Patel * 80131ab09b4SDipen Patel * Returns: 0 on success or a negative error code on failure. 80231ab09b4SDipen Patel */ 80331ab09b4SDipen Patel int hte_push_ts_ns(const struct hte_chip *chip, u32 xlated_id, 80431ab09b4SDipen Patel struct hte_ts_data *data) 80531ab09b4SDipen Patel { 80631ab09b4SDipen Patel enum hte_return ret; 80731ab09b4SDipen Patel int st = 0; 80831ab09b4SDipen Patel struct hte_ts_info *ei; 80931ab09b4SDipen Patel unsigned long flag; 81031ab09b4SDipen Patel 81131ab09b4SDipen Patel if (!chip || !data || !chip->gdev) 81231ab09b4SDipen Patel return -EINVAL; 81331ab09b4SDipen Patel 814e30b64a3SDan Carpenter if (xlated_id >= chip->nlines) 81531ab09b4SDipen Patel return -EINVAL; 81631ab09b4SDipen Patel 81731ab09b4SDipen Patel ei = &chip->gdev->ei[xlated_id]; 81831ab09b4SDipen Patel 81931ab09b4SDipen Patel spin_lock_irqsave(&ei->slock, flag); 82031ab09b4SDipen Patel 82131ab09b4SDipen Patel /* timestamp sequence counter */ 82231ab09b4SDipen Patel data->seq = ei->seq++; 82331ab09b4SDipen Patel 82431ab09b4SDipen Patel if (!test_bit(HTE_TS_REGISTERED, &ei->flags) || 82531ab09b4SDipen Patel test_bit(HTE_TS_DISABLE, &ei->flags)) { 82631ab09b4SDipen Patel dev_dbg(chip->dev, "Unknown timestamp push\n"); 82731ab09b4SDipen Patel atomic_inc(&ei->dropped_ts); 82831ab09b4SDipen Patel st = -EINVAL; 82931ab09b4SDipen Patel goto unlock; 83031ab09b4SDipen Patel } 83131ab09b4SDipen Patel 83231ab09b4SDipen Patel ret = ei->cb(data, ei->cl_data); 83331ab09b4SDipen Patel if (ret == HTE_RUN_SECOND_CB && ei->tcb) { 83431ab09b4SDipen Patel queue_work(system_unbound_wq, &ei->cb_work); 83531ab09b4SDipen Patel set_bit(HTE_TS_QUEUE_WK, &ei->flags); 83631ab09b4SDipen Patel } 83731ab09b4SDipen Patel 83831ab09b4SDipen Patel unlock: 83931ab09b4SDipen Patel spin_unlock_irqrestore(&ei->slock, flag); 84031ab09b4SDipen Patel 84131ab09b4SDipen Patel return st; 84231ab09b4SDipen Patel } 84331ab09b4SDipen Patel EXPORT_SYMBOL_GPL(hte_push_ts_ns); 84431ab09b4SDipen Patel 84531ab09b4SDipen Patel static int hte_register_chip(struct hte_chip *chip) 84631ab09b4SDipen Patel { 84731ab09b4SDipen Patel struct hte_device *gdev; 84831ab09b4SDipen Patel u32 i; 84931ab09b4SDipen Patel 85031ab09b4SDipen Patel if (!chip || !chip->dev || !chip->dev->of_node) 85131ab09b4SDipen Patel return -EINVAL; 85231ab09b4SDipen Patel 85331ab09b4SDipen Patel if (!chip->ops || !chip->ops->request || !chip->ops->release) { 85431ab09b4SDipen Patel dev_err(chip->dev, "Driver needs to provide ops\n"); 85531ab09b4SDipen Patel return -EINVAL; 85631ab09b4SDipen Patel } 85731ab09b4SDipen Patel 85831ab09b4SDipen Patel gdev = kzalloc(struct_size(gdev, ei, chip->nlines), GFP_KERNEL); 85931ab09b4SDipen Patel if (!gdev) 86031ab09b4SDipen Patel return -ENOMEM; 86131ab09b4SDipen Patel 86231ab09b4SDipen Patel gdev->chip = chip; 86331ab09b4SDipen Patel chip->gdev = gdev; 86431ab09b4SDipen Patel gdev->nlines = chip->nlines; 86531ab09b4SDipen Patel gdev->sdev = chip->dev; 86631ab09b4SDipen Patel 86731ab09b4SDipen Patel for (i = 0; i < chip->nlines; i++) { 86831ab09b4SDipen Patel gdev->ei[i].gdev = gdev; 86931ab09b4SDipen Patel mutex_init(&gdev->ei[i].req_mlock); 87031ab09b4SDipen Patel spin_lock_init(&gdev->ei[i].slock); 87131ab09b4SDipen Patel } 87231ab09b4SDipen Patel 87331ab09b4SDipen Patel if (chip->dev->driver) 87431ab09b4SDipen Patel gdev->owner = chip->dev->driver->owner; 87531ab09b4SDipen Patel else 87631ab09b4SDipen Patel gdev->owner = THIS_MODULE; 87731ab09b4SDipen Patel 87831ab09b4SDipen Patel of_node_get(chip->dev->of_node); 87931ab09b4SDipen Patel 88031ab09b4SDipen Patel INIT_LIST_HEAD(&gdev->list); 88131ab09b4SDipen Patel 88231ab09b4SDipen Patel spin_lock(&hte_lock); 88331ab09b4SDipen Patel list_add_tail(&gdev->list, &hte_devices); 88431ab09b4SDipen Patel spin_unlock(&hte_lock); 88531ab09b4SDipen Patel 88631ab09b4SDipen Patel hte_chip_dbgfs_init(gdev); 88731ab09b4SDipen Patel 88831ab09b4SDipen Patel dev_dbg(chip->dev, "Added hte chip\n"); 88931ab09b4SDipen Patel 89031ab09b4SDipen Patel return 0; 89131ab09b4SDipen Patel } 89231ab09b4SDipen Patel 89331ab09b4SDipen Patel static int hte_unregister_chip(struct hte_chip *chip) 89431ab09b4SDipen Patel { 89531ab09b4SDipen Patel struct hte_device *gdev; 89631ab09b4SDipen Patel 89731ab09b4SDipen Patel if (!chip) 89831ab09b4SDipen Patel return -EINVAL; 89931ab09b4SDipen Patel 90031ab09b4SDipen Patel gdev = chip->gdev; 90131ab09b4SDipen Patel 90231ab09b4SDipen Patel spin_lock(&hte_lock); 90331ab09b4SDipen Patel list_del(&gdev->list); 90431ab09b4SDipen Patel spin_unlock(&hte_lock); 90531ab09b4SDipen Patel 90631ab09b4SDipen Patel gdev->chip = NULL; 90731ab09b4SDipen Patel 90831ab09b4SDipen Patel of_node_put(chip->dev->of_node); 90931ab09b4SDipen Patel debugfs_remove_recursive(gdev->dbg_root); 91031ab09b4SDipen Patel kfree(gdev); 91131ab09b4SDipen Patel 91231ab09b4SDipen Patel dev_dbg(chip->dev, "Removed hte chip\n"); 91331ab09b4SDipen Patel 91431ab09b4SDipen Patel return 0; 91531ab09b4SDipen Patel } 91631ab09b4SDipen Patel 91731ab09b4SDipen Patel static void _hte_devm_unregister_chip(void *chip) 91831ab09b4SDipen Patel { 91931ab09b4SDipen Patel hte_unregister_chip(chip); 92031ab09b4SDipen Patel } 92131ab09b4SDipen Patel 92231ab09b4SDipen Patel /** 92331ab09b4SDipen Patel * devm_hte_register_chip() - Resource managed API to register HTE chip. 92431ab09b4SDipen Patel * 92531ab09b4SDipen Patel * It is used by the provider to register itself with the HTE subsystem. 92631ab09b4SDipen Patel * The unregistration is done automatically when the provider exits. 92731ab09b4SDipen Patel * 92831ab09b4SDipen Patel * @chip: the HTE chip to add to subsystem. 92931ab09b4SDipen Patel * 93031ab09b4SDipen Patel * Returns: 0 on success or a negative error code on failure. 93131ab09b4SDipen Patel */ 93231ab09b4SDipen Patel int devm_hte_register_chip(struct hte_chip *chip) 93331ab09b4SDipen Patel { 93431ab09b4SDipen Patel int err; 93531ab09b4SDipen Patel 93631ab09b4SDipen Patel err = hte_register_chip(chip); 93731ab09b4SDipen Patel if (err) 93831ab09b4SDipen Patel return err; 93931ab09b4SDipen Patel 94031ab09b4SDipen Patel err = devm_add_action_or_reset(chip->dev, _hte_devm_unregister_chip, 94131ab09b4SDipen Patel chip); 94231ab09b4SDipen Patel if (err) 94331ab09b4SDipen Patel return err; 94431ab09b4SDipen Patel 94531ab09b4SDipen Patel return 0; 94631ab09b4SDipen Patel } 94731ab09b4SDipen Patel EXPORT_SYMBOL_GPL(devm_hte_register_chip); 948