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