13ce53722SRobert Mustacchi /* 23ce53722SRobert Mustacchi * This file and its contents are supplied under the terms of the 33ce53722SRobert Mustacchi * Common Development and Distribution License ("CDDL"), version 1.0. 43ce53722SRobert Mustacchi * You may only use this file in accordance with the terms of version 53ce53722SRobert Mustacchi * 1.0 of the CDDL. 63ce53722SRobert Mustacchi * 73ce53722SRobert Mustacchi * A full copy of the text of the CDDL should have accompanied this 83ce53722SRobert Mustacchi * source. A copy of the CDDL is also available via the Internet at 93ce53722SRobert Mustacchi * http://www.illumos.org/license/CDDL. 103ce53722SRobert Mustacchi */ 113ce53722SRobert Mustacchi 123ce53722SRobert Mustacchi /* 133ce53722SRobert Mustacchi * Copyright 2020 Oxide Computer Company 143ce53722SRobert Mustacchi */ 153ce53722SRobert Mustacchi 163ce53722SRobert Mustacchi /* 173ce53722SRobert Mustacchi * Kernel Sensor Framework 183ce53722SRobert Mustacchi * 193ce53722SRobert Mustacchi * The kernel sensor framework exists to provide a simple and straightforward 203ce53722SRobert Mustacchi * means for various parts of the system to declare and instantiate sensor 213ce53722SRobert Mustacchi * information. Between this and the ksensor character device 223ce53722SRobert Mustacchi * (uts/common/io/ksensor/ksensor_drv.c) this exposes per-device sensors and 233ce53722SRobert Mustacchi * character devices. 243ce53722SRobert Mustacchi * 253ce53722SRobert Mustacchi * -------------------------- 263ce53722SRobert Mustacchi * Driver and User Interfaces 273ce53722SRobert Mustacchi * -------------------------- 283ce53722SRobert Mustacchi * 293ce53722SRobert Mustacchi * Each sensor that is registered with the framework is exposed as a character 303ce53722SRobert Mustacchi * device under /dev/sensors. The device class and node name are often ':' 313ce53722SRobert Mustacchi * delineated and must begin with 'ddi_sensor'. Everything after 'ddi_sensor' 323ce53722SRobert Mustacchi * will be created in a directory under /dev/sensors. So for example the Intel 333ce53722SRobert Mustacchi * PCH driver uses a class "ddi_sensor:temperature:pch" and a node name of 343ce53722SRobert Mustacchi * 'ts.%d'. This creates the node /dev/sensors/temperature/pch/ts.0. The 353ce53722SRobert Mustacchi * devfsadm plugin automatically handles the creation of directories which makes 363ce53722SRobert Mustacchi * the addition of additional sensor types easy to create. 373ce53722SRobert Mustacchi * 383ce53722SRobert Mustacchi * Strictly speaking, any device can manage their own sensors and minor nodes by 393ce53722SRobert Mustacchi * using the appropriate class and implementing the corresponding ioctls. That 403ce53722SRobert Mustacchi * was how the first kernel sensors were written; however, there are a lot of 413ce53722SRobert Mustacchi * issues with that which led to this: 423ce53722SRobert Mustacchi * 433ce53722SRobert Mustacchi * 1. Every driver had to actually implement character devices. 443ce53722SRobert Mustacchi * 453ce53722SRobert Mustacchi * 2. Every driver had to duplicate a lot of the logic around open(9E), 463ce53722SRobert Mustacchi * close(9E), and ioctl(9E). 473ce53722SRobert Mustacchi * 483ce53722SRobert Mustacchi * 3. Drivers that tied into frameworks like mac(9E) or SCSAv3 needed a lot more 493ce53722SRobert Mustacchi * work to fit into this model. For example, because the minor state is 503ce53722SRobert Mustacchi * shared between all the instances and the frameworks, they would have 513ce53722SRobert Mustacchi * required shared, global state that they don't have today. 523ce53722SRobert Mustacchi * 533ce53722SRobert Mustacchi * Ultimately, having an operations vector and a callback argument makes work a 543ce53722SRobert Mustacchi * lot simpler for the producers of sensor data and that simplicity makes it 553ce53722SRobert Mustacchi * worthwhile to take on additional effort and work here. 563ce53722SRobert Mustacchi * 573ce53722SRobert Mustacchi * ---------- 583ce53722SRobert Mustacchi * Components 593ce53722SRobert Mustacchi * ---------- 603ce53722SRobert Mustacchi * 613ce53722SRobert Mustacchi * The ksensor framework is made of a couple of different pieces: 623ce53722SRobert Mustacchi * 633ce53722SRobert Mustacchi * 1. This glue that is a part of genunix. 643ce53722SRobert Mustacchi * 2. The ksensor character device driver. 653ce53722SRobert Mustacchi * 3. Sensor providers, which are generally drivers that register with the 663ce53722SRobert Mustacchi * ksensor framework. 673ce53722SRobert Mustacchi * 683ce53722SRobert Mustacchi * The implementation of (1) is all in this file. The implementation of (2) is 693ce53722SRobert Mustacchi * in uts/common/io/ksensor/ksensor_drv.c. The implementation of (3) is found in 703ce53722SRobert Mustacchi * all of the different leaf devices. Examples of (3) include pchtemp(7D) and 713ce53722SRobert Mustacchi * igb(7D). 723ce53722SRobert Mustacchi * 733ce53722SRobert Mustacchi * We separate numbers one and two into two different components for a few 743ce53722SRobert Mustacchi * reasons. The most important thing is that drivers that provide sensors should 753ce53722SRobert Mustacchi * not be dependent on some other part of the system having been loaded. This 763ce53722SRobert Mustacchi * makes a compelling argument for it being a part of the core kernel. However, 773ce53722SRobert Mustacchi * like other subsystems (e.g. kstats, smbios, etc.), it's useful to separate 783ce53722SRobert Mustacchi * out the thing that provides the interface to users with the thing that is 793ce53722SRobert Mustacchi * used to glue together providers in the kernel. There's the added benefit that 803ce53722SRobert Mustacchi * it's practically simpler to spin up a pseudo-device through a module. 813ce53722SRobert Mustacchi * 823ce53722SRobert Mustacchi * The ksensor character device driver (2) registers with the main genunix 833ce53722SRobert Mustacchi * ksensor code (1) when it attaches and when it detaches. The kernel only 843ce53722SRobert Mustacchi * allows a single driver to be attached to it. When that character device 853ce53722SRobert Mustacchi * driver attaches, the ksensor framework will walk through all of the currently 863ce53722SRobert Mustacchi * registered sensors and inform the character device driver of the nodes that 873ce53722SRobert Mustacchi * it needs to create. While the character device driver is attached, the 883ce53722SRobert Mustacchi * ksensor framework will also call back into it when a sensor needs to be 893ce53722SRobert Mustacchi * removed. 903ce53722SRobert Mustacchi * 913ce53722SRobert Mustacchi * Generally speaking, this distinction of responsibilities allows the kernel 923ce53722SRobert Mustacchi * sensor character device driver to attach and detach without impact to the 933ce53722SRobert Mustacchi * sensor providers or them even being notified at all, it's all transparent to 943ce53722SRobert Mustacchi * them. 953ce53722SRobert Mustacchi * 963ce53722SRobert Mustacchi * ------------------------------ 973ce53722SRobert Mustacchi * Sensor Lifetime and detach(9E) 983ce53722SRobert Mustacchi * ------------------------------ 993ce53722SRobert Mustacchi * 1003ce53722SRobert Mustacchi * Traditionally, a device driver may be detached by the broader kernel whenever 1013ce53722SRobert Mustacchi * the kernel desires it. On debug builds this happens by a dedicated thread. On 1023ce53722SRobert Mustacchi * a non-debug build this may happen due to memory pressure or as an attempt to 1033ce53722SRobert Mustacchi * reclaim idle resources (though this is much less common). However, when the 1043ce53722SRobert Mustacchi * module is detached, the system remembers that minor nodes previously existed 1053ce53722SRobert Mustacchi * and that entries in /devices had been created. When something proceeds to 1063ce53722SRobert Mustacchi * access an entry in /devices again, the system will use that to bring a driver 1073ce53722SRobert Mustacchi * back to life. It doesn't matter whether it's a pseudo-device driver or 1083ce53722SRobert Mustacchi * something else, this can happen. 1093ce53722SRobert Mustacchi * 1103ce53722SRobert Mustacchi * One downside to the sensor framework, is that we need to emulate this 1113ce53722SRobert Mustacchi * behavior which leads to some amount of complexity here. But this is a 1123ce53722SRobert Mustacchi * worthwhile tradeoff as it makes things much simpler for providers and it's 1133ce53722SRobert Mustacchi * not too hard for us to emulate this behavior. 1143ce53722SRobert Mustacchi * 1153ce53722SRobert Mustacchi * When a sensor provider registers the sensor, the sensor becomes available to 1163ce53722SRobert Mustacchi * the system. When the sensor provider unregisters with the system, which 1173ce53722SRobert Mustacchi * happens during its detach routine, then we note that it has been detached; 1183ce53722SRobert Mustacchi * however, we don't delete its minor node and if something accesses it, we 1193ce53722SRobert Mustacchi * attempt to load the driver again, the same way that devfs (the file system 1203ce53722SRobert Mustacchi * behind /devices) does. 1213ce53722SRobert Mustacchi * 1223ce53722SRobert Mustacchi * For each dev_info_t that registers a sensor we register a callback such that 1233ce53722SRobert Mustacchi * when the device is removed, e.g. someone called rem_drv or physically pulls 1243ce53722SRobert Mustacchi * the device, then we'll be able to finally clean up the device. This lifetime 1253ce53722SRobert Mustacchi * can be represented in the following image: 1263ce53722SRobert Mustacchi * 1273ce53722SRobert Mustacchi * | 1283ce53722SRobert Mustacchi * | 1293ce53722SRobert Mustacchi * +-----<-------------------------------------+ 1303ce53722SRobert Mustacchi * | | 1313ce53722SRobert Mustacchi * | . . call ksensor_create() | 1323ce53722SRobert Mustacchi * v | 1333ce53722SRobert Mustacchi * +-------+ | 1343ce53722SRobert Mustacchi * | Valid | | 1353ce53722SRobert Mustacchi * +-------+ | 1363ce53722SRobert Mustacchi * | ^ 1373ce53722SRobert Mustacchi * | . . call ksensor_remove() | 1383ce53722SRobert Mustacchi * v | 1393ce53722SRobert Mustacchi * +---------+ | 1403ce53722SRobert Mustacchi * | Invalid | | 1413ce53722SRobert Mustacchi * +---------+ | 1423ce53722SRobert Mustacchi * | | | 1433ce53722SRobert Mustacchi * | | . . user uses sensor again | 1443ce53722SRobert Mustacchi * | | | 1453ce53722SRobert Mustacchi * | +-------------------+ | 1463ce53722SRobert Mustacchi * | | | 1473ce53722SRobert Mustacchi * | v | 1483ce53722SRobert Mustacchi * | +---------------+ | 1493ce53722SRobert Mustacchi * | | Attatching... |-->---------+ 1503ce53722SRobert Mustacchi * | +---------------+ 1513ce53722SRobert Mustacchi * | . . ddi unbind cb | 1523ce53722SRobert Mustacchi * | | 1533ce53722SRobert Mustacchi * v | . . attatch fails or 1543ce53722SRobert Mustacchi * +---------+ | no call to ksensor_create() 1553ce53722SRobert Mustacchi * | Deleted |--<---------------+ again 1563ce53722SRobert Mustacchi * +---------+ 1573ce53722SRobert Mustacchi * 1583ce53722SRobert Mustacchi * When the DDI unbind callback is called, we know that the device is going to 1593ce53722SRobert Mustacchi * be removed. However, this happens within a subtle context with a majority of 1603ce53722SRobert Mustacchi * the device tree held (at least the dip's parent). In particular, another 1613ce53722SRobert Mustacchi * thread may be trying to obtain a hold on it and be blocked in 1623ce53722SRobert Mustacchi * ndi_devi_enter(). As the callback thread holds that, that could lead to a 1633ce53722SRobert Mustacchi * deadlock. As a result, we clean things up in two phases. One during the 1643ce53722SRobert Mustacchi * synchronous callback and the other via a taskq. In the first phase we 1653ce53722SRobert Mustacchi * logically do the following: 1663ce53722SRobert Mustacchi * 1673ce53722SRobert Mustacchi * o Remove the dip from the list of ksensor dips and set the flag that 1683ce53722SRobert Mustacchi * indicates that it's been removed. 1693ce53722SRobert Mustacchi * o Remove all of the sensors from the global avl to make sure that new 1703ce53722SRobert Mustacchi * threads cannot look it up. 1713ce53722SRobert Mustacchi * 1723ce53722SRobert Mustacchi * Then, after the taskq is dispatched, we do the following in taskq context: 1733ce53722SRobert Mustacchi * 1743ce53722SRobert Mustacchi * o Tell the ksensor driver that it should remove the minor node. 1753ce53722SRobert Mustacchi * o Block on each sensor until it is no-longer busy and then clean it up. 1763ce53722SRobert Mustacchi * o Clean up the ksensor_dip_t. 1773ce53722SRobert Mustacchi * 1783ce53722SRobert Mustacchi * ------------------ 1793ce53722SRobert Mustacchi * Accessing a Sensor 1803ce53722SRobert Mustacchi * ------------------ 1813ce53722SRobert Mustacchi * 1823ce53722SRobert Mustacchi * Access to a particular sensor is serialized in the system. In addition to 1833ce53722SRobert Mustacchi * that, a number of steps are required to access one that is not unlike 1843ce53722SRobert Mustacchi * accessing a character device. When a given sensor is held the KSENSOR_F_BUSY 1853ce53722SRobert Mustacchi * flag is set in the ksensor_flags member. In addition, as part of taking a 1863ce53722SRobert Mustacchi * hold a number of side effects occur that ensure that the sensor provider's 1873ce53722SRobert Mustacchi * dev_info_t is considered busy and can't be detached. 1883ce53722SRobert Mustacchi * 1893ce53722SRobert Mustacchi * To obtain a hold on a sensor the following logical steps are required (see 1903ce53722SRobert Mustacchi * ksensor_hold_by_id() for the implementation): 1913ce53722SRobert Mustacchi * 1923ce53722SRobert Mustacchi * 1. Map the minor to the ksensor_t via the avl tree 1933ce53722SRobert Mustacchi * 2. Check that the ksensor's dip is valid 1943ce53722SRobert Mustacchi * 3. If the sensor is busy, wait until it is no longer so, and restart from 1953ce53722SRobert Mustacchi * the top. Otherwise, mark the sensor as busy. 1963ce53722SRobert Mustacchi * 4. Enter the parent and place a hold on the sensor provider's dip. 1973ce53722SRobert Mustacchi * 5. Once again check if the dip is removed or not because we have to drop 1983ce53722SRobert Mustacchi * locks during that operation. 1993ce53722SRobert Mustacchi * 6. Check if the ksensor has the valid flag set. If not, attempt to configure 2003ce53722SRobert Mustacchi * the dip. 2013ce53722SRobert Mustacchi * 7. Assuming the sensor is now valid, we can return it. 2023ce53722SRobert Mustacchi * 2033ce53722SRobert Mustacchi * After this point, the sensor is considered valid for use. Once the consumer 2043ce53722SRobert Mustacchi * is finished with the sensor, it should be released by calling 2053ce53722SRobert Mustacchi * ksensor_release(). 2063ce53722SRobert Mustacchi * 2073ce53722SRobert Mustacchi * An important aspect of the above scheme is that the KSENSOR_F_BUSY flag is 2083ce53722SRobert Mustacchi * required to progress through the validation and holding of the device. This 2093ce53722SRobert Mustacchi * makes sure that only one thread is attempting to attach it at a given time. A 2103ce53722SRobert Mustacchi * reasonable future optimization would be to amortize this cost in open(9E) 2113ce53722SRobert Mustacchi * and close(9E) of the minor and to bump a count as it being referenced as long 2123ce53722SRobert Mustacchi * as it is open. 2133ce53722SRobert Mustacchi * 2143ce53722SRobert Mustacchi * ----------------------------- 2153ce53722SRobert Mustacchi * Character Device Registration 2163ce53722SRobert Mustacchi * ----------------------------- 2173ce53722SRobert Mustacchi * 2183ce53722SRobert Mustacchi * The 'ksensor' character device driver can come and go. To support this, the 2193ce53722SRobert Mustacchi * ksensor framework communicates with the ksensor character device by a 2203ce53722SRobert Mustacchi * well-defined set of callbacks, used to indicate sensor addition and removal. 2213ce53722SRobert Mustacchi * The ksensor character device is found in uts/common/io/ksensor/ksensor_drv.c. 2223ce53722SRobert Mustacchi * The ksensor character device is responsible for creating and destroying minor 2233ce53722SRobert Mustacchi * nodes. 2243ce53722SRobert Mustacchi * 2253ce53722SRobert Mustacchi * Each ksensor_t has a flag, KSENSOR_F_NOTIFIED, that is used to indicate 2263ce53722SRobert Mustacchi * whether or not the registered driver has been notified of the sensor. When a 2273ce53722SRobert Mustacchi * callback is first registered, we'll walk through the entire list of nodes to 2283ce53722SRobert Mustacchi * make sure that its minor has been created. When unregistering, the minor node 2293ce53722SRobert Mustacchi * remove callback will not be called; however, this can generally by dealt with 2303ce53722SRobert Mustacchi * by calling something like ddi_remove_minor_node(dip, NULL). 2313ce53722SRobert Mustacchi * 2323ce53722SRobert Mustacchi * ------- 2333ce53722SRobert Mustacchi * Locking 2343ce53722SRobert Mustacchi * ------- 2353ce53722SRobert Mustacchi * 2363ce53722SRobert Mustacchi * The following rules apply to dealing with lock ordering: 2373ce53722SRobert Mustacchi * 2383ce53722SRobert Mustacchi * 1. The global ksensor_g_mutex protects all global data and must be taken 2393ce53722SRobert Mustacchi * before a ksensor_t's individual mutex. 2403ce53722SRobert Mustacchi * 2413ce53722SRobert Mustacchi * 2. A thread should not hold any two ksensor_t's mutex at any time. 2423ce53722SRobert Mustacchi * 2433ce53722SRobert Mustacchi * 3. No locks should be held when attempting to grab or manipulate a 2443ce53722SRobert Mustacchi * dev_info_t, e.g. ndi_devi_enter(). 2453ce53722SRobert Mustacchi * 2463ce53722SRobert Mustacchi * 4. Unless the ksensor is actively being held, whenever a ksensor is found, 2473ce53722SRobert Mustacchi * one must check whether the ksensor_dip_t flag KSENSOR_DIP_F_REMOVED is 2483ce53722SRobert Mustacchi * set or not and whether the ksensor_t's KSENSOR_F_VALID flag is set. 2493ce53722SRobert Mustacchi */ 2503ce53722SRobert Mustacchi 2513ce53722SRobert Mustacchi #include <sys/types.h> 2523ce53722SRobert Mustacchi #include <sys/file.h> 2533ce53722SRobert Mustacchi #include <sys/errno.h> 2543ce53722SRobert Mustacchi #include <sys/cred.h> 2553ce53722SRobert Mustacchi #include <sys/ddi.h> 2563ce53722SRobert Mustacchi #include <sys/stat.h> 2573ce53722SRobert Mustacchi #include <sys/sunddi.h> 2583ce53722SRobert Mustacchi #include <sys/sunndi.h> 2593ce53722SRobert Mustacchi #include <sys/esunddi.h> 2603ce53722SRobert Mustacchi #include <sys/ksensor_impl.h> 2613ce53722SRobert Mustacchi #include <sys/ddi_impldefs.h> 2623ce53722SRobert Mustacchi #include <sys/pci.h> 2633ce53722SRobert Mustacchi #include <sys/avl.h> 2643ce53722SRobert Mustacchi #include <sys/list.h> 2653ce53722SRobert Mustacchi #include <sys/stddef.h> 2663ce53722SRobert Mustacchi #include <sys/sysmacros.h> 2673ce53722SRobert Mustacchi #include <sys/fs/dv_node.h> 2683ce53722SRobert Mustacchi 2693ce53722SRobert Mustacchi typedef enum { 2703ce53722SRobert Mustacchi /* 2713ce53722SRobert Mustacchi * This flag indicates that the subscribing ksensor character device has 2723ce53722SRobert Mustacchi * been notified about this flag. 2733ce53722SRobert Mustacchi */ 2743ce53722SRobert Mustacchi KSENSOR_F_NOTIFIED = 1 << 0, 2753ce53722SRobert Mustacchi /* 2763ce53722SRobert Mustacchi * This indicates that the sensor is currently valid, meaning that the 2773ce53722SRobert Mustacchi * ops vector and argument are safe to use. This is removed when a 2783ce53722SRobert Mustacchi * driver with a sensor is detached. 2793ce53722SRobert Mustacchi */ 2803ce53722SRobert Mustacchi KSENSOR_F_VALID = 1 << 1, 2813ce53722SRobert Mustacchi /* 2823ce53722SRobert Mustacchi * Indicates that a client has a hold on the sensor for some purpose. 2833ce53722SRobert Mustacchi * This must be set before trying to get an NDI hold. Once this is set 2843ce53722SRobert Mustacchi * and a NDI hold is in place, it is safe to use the operations vector 2853ce53722SRobert Mustacchi * and argument. 2863ce53722SRobert Mustacchi */ 2873ce53722SRobert Mustacchi KSENSOR_F_BUSY = 1 << 2, 2883ce53722SRobert Mustacchi } ksensor_flags_t; 2893ce53722SRobert Mustacchi 2903ce53722SRobert Mustacchi typedef enum { 2913ce53722SRobert Mustacchi KSENSOR_DIP_F_REMOVED = 1 << 0 2923ce53722SRobert Mustacchi } ksensor_dip_flags_t; 2933ce53722SRobert Mustacchi 2943ce53722SRobert Mustacchi typedef struct { 2953ce53722SRobert Mustacchi list_node_t ksdip_link; 2963ce53722SRobert Mustacchi ksensor_dip_flags_t ksdip_flags; 2973ce53722SRobert Mustacchi dev_info_t *ksdip_dip; 2983ce53722SRobert Mustacchi ddi_unbind_callback_t ksdip_cb; 2993ce53722SRobert Mustacchi list_t ksdip_sensors; 3003ce53722SRobert Mustacchi } ksensor_dip_t; 3013ce53722SRobert Mustacchi 3023ce53722SRobert Mustacchi typedef struct { 3033ce53722SRobert Mustacchi kmutex_t ksensor_mutex; 3043ce53722SRobert Mustacchi kcondvar_t ksensor_cv; 3053ce53722SRobert Mustacchi ksensor_flags_t ksensor_flags; 3063ce53722SRobert Mustacchi list_node_t ksensor_dip_list; 3073ce53722SRobert Mustacchi avl_node_t ksensor_id_avl; 3083ce53722SRobert Mustacchi uint_t ksensor_nwaiters; 3093ce53722SRobert Mustacchi ksensor_dip_t *ksensor_ksdip; 3103ce53722SRobert Mustacchi char *ksensor_name; 3113ce53722SRobert Mustacchi char *ksensor_class; 3123ce53722SRobert Mustacchi id_t ksensor_id; 3133ce53722SRobert Mustacchi const ksensor_ops_t *ksensor_ops; 3143ce53722SRobert Mustacchi void *ksensor_arg; 3153ce53722SRobert Mustacchi } ksensor_t; 3163ce53722SRobert Mustacchi 3173ce53722SRobert Mustacchi static kmutex_t ksensor_g_mutex; 3183ce53722SRobert Mustacchi static id_space_t *ksensor_ids; 3193ce53722SRobert Mustacchi static list_t ksensor_dips; 3203ce53722SRobert Mustacchi static avl_tree_t ksensor_avl; 3213ce53722SRobert Mustacchi static dev_info_t *ksensor_cb_dip; 3223ce53722SRobert Mustacchi static ksensor_create_f ksensor_cb_create; 3233ce53722SRobert Mustacchi static ksensor_remove_f ksensor_cb_remove; 3243ce53722SRobert Mustacchi 3253ce53722SRobert Mustacchi static int 3263ce53722SRobert Mustacchi ksensor_avl_compare(const void *l, const void *r) 3273ce53722SRobert Mustacchi { 3283ce53722SRobert Mustacchi const ksensor_t *kl = l; 3293ce53722SRobert Mustacchi const ksensor_t *kr = r; 3303ce53722SRobert Mustacchi 3313ce53722SRobert Mustacchi if (kl->ksensor_id > kr->ksensor_id) { 3323ce53722SRobert Mustacchi return (1); 3333ce53722SRobert Mustacchi } else if (kl->ksensor_id < kr->ksensor_id) { 3343ce53722SRobert Mustacchi return (-1); 3353ce53722SRobert Mustacchi } else { 3363ce53722SRobert Mustacchi return (0); 3373ce53722SRobert Mustacchi } 3383ce53722SRobert Mustacchi } 3393ce53722SRobert Mustacchi 3403ce53722SRobert Mustacchi static ksensor_t * 3413ce53722SRobert Mustacchi ksensor_find_by_id(id_t id) 3423ce53722SRobert Mustacchi { 3433ce53722SRobert Mustacchi ksensor_t k, *ret; 3443ce53722SRobert Mustacchi 3453ce53722SRobert Mustacchi ASSERT(MUTEX_HELD(&ksensor_g_mutex)); 3463ce53722SRobert Mustacchi 3473ce53722SRobert Mustacchi k.ksensor_id = id; 3483ce53722SRobert Mustacchi return (avl_find(&ksensor_avl, &k, NULL)); 3493ce53722SRobert Mustacchi 3503ce53722SRobert Mustacchi } 3513ce53722SRobert Mustacchi 3523ce53722SRobert Mustacchi static ksensor_t * 3533ce53722SRobert Mustacchi ksensor_search_ksdip(ksensor_dip_t *ksdip, const char *name, const char *class) 3543ce53722SRobert Mustacchi { 3553ce53722SRobert Mustacchi ksensor_t *s; 3563ce53722SRobert Mustacchi 3573ce53722SRobert Mustacchi ASSERT(MUTEX_HELD(&ksensor_g_mutex)); 3583ce53722SRobert Mustacchi 3593ce53722SRobert Mustacchi for (s = list_head(&ksdip->ksdip_sensors); s != NULL; 3603ce53722SRobert Mustacchi s = list_next(&ksdip->ksdip_sensors, s)) { 3613ce53722SRobert Mustacchi if (strcmp(s->ksensor_name, name) == 0 && 3623ce53722SRobert Mustacchi strcmp(s->ksensor_class, class) == 0) { 3633ce53722SRobert Mustacchi return (s); 3643ce53722SRobert Mustacchi } 3653ce53722SRobert Mustacchi } 3663ce53722SRobert Mustacchi 3673ce53722SRobert Mustacchi return (NULL); 3683ce53722SRobert Mustacchi } 3693ce53722SRobert Mustacchi 3703ce53722SRobert Mustacchi static void 3713ce53722SRobert Mustacchi ksensor_free_sensor(ksensor_t *sensor) 3723ce53722SRobert Mustacchi { 3733ce53722SRobert Mustacchi strfree(sensor->ksensor_name); 3743ce53722SRobert Mustacchi strfree(sensor->ksensor_class); 3753ce53722SRobert Mustacchi id_free(ksensor_ids, sensor->ksensor_id); 3763ce53722SRobert Mustacchi mutex_destroy(&sensor->ksensor_mutex); 3773ce53722SRobert Mustacchi kmem_free(sensor, sizeof (ksensor_t)); 3783ce53722SRobert Mustacchi } 3793ce53722SRobert Mustacchi 3803ce53722SRobert Mustacchi static void 3813ce53722SRobert Mustacchi ksensor_free_dip(ksensor_dip_t *ksdip) 3823ce53722SRobert Mustacchi { 3833ce53722SRobert Mustacchi list_destroy(&ksdip->ksdip_sensors); 3843ce53722SRobert Mustacchi kmem_free(ksdip, sizeof (ksensor_dip_t)); 3853ce53722SRobert Mustacchi } 3863ce53722SRobert Mustacchi 3873ce53722SRobert Mustacchi static void 3883ce53722SRobert Mustacchi ksensor_dip_unbind_taskq(void *arg) 3893ce53722SRobert Mustacchi { 3903ce53722SRobert Mustacchi ksensor_dip_t *k = arg; 3913ce53722SRobert Mustacchi ksensor_t *sensor; 3923ce53722SRobert Mustacchi 3933ce53722SRobert Mustacchi /* 3943ce53722SRobert Mustacchi * First notify an attached driver that the nodes are going away 3953ce53722SRobert Mustacchi * before we block and wait on them. 3963ce53722SRobert Mustacchi */ 3973ce53722SRobert Mustacchi mutex_enter(&ksensor_g_mutex); 3983ce53722SRobert Mustacchi for (sensor = list_head(&k->ksdip_sensors); sensor != NULL; 3993ce53722SRobert Mustacchi sensor = list_next(&k->ksdip_sensors, sensor)) { 4003ce53722SRobert Mustacchi mutex_enter(&sensor->ksensor_mutex); 4013ce53722SRobert Mustacchi if (sensor->ksensor_flags & KSENSOR_F_NOTIFIED) { 4023ce53722SRobert Mustacchi ksensor_cb_remove(sensor->ksensor_id, 4033ce53722SRobert Mustacchi sensor->ksensor_name); 4043ce53722SRobert Mustacchi sensor->ksensor_flags &= ~KSENSOR_F_NOTIFIED; 4053ce53722SRobert Mustacchi } 4063ce53722SRobert Mustacchi mutex_exit(&sensor->ksensor_mutex); 4073ce53722SRobert Mustacchi } 4083ce53722SRobert Mustacchi mutex_exit(&ksensor_g_mutex); 4093ce53722SRobert Mustacchi 4103ce53722SRobert Mustacchi /* 4113ce53722SRobert Mustacchi * Now that the driver has destroyed its minor, wait for anything that's 4123ce53722SRobert Mustacchi * still there. 4133ce53722SRobert Mustacchi */ 4143ce53722SRobert Mustacchi while ((sensor = list_remove_head(&k->ksdip_sensors)) != NULL) { 4153ce53722SRobert Mustacchi mutex_enter(&sensor->ksensor_mutex); 4163ce53722SRobert Mustacchi while ((sensor->ksensor_flags & KSENSOR_F_BUSY) != 0 || 4173ce53722SRobert Mustacchi sensor->ksensor_nwaiters > 0) { 4183ce53722SRobert Mustacchi cv_wait(&sensor->ksensor_cv, &sensor->ksensor_mutex); 4193ce53722SRobert Mustacchi } 4203ce53722SRobert Mustacchi mutex_exit(&sensor->ksensor_mutex); 4213ce53722SRobert Mustacchi ksensor_free_sensor(sensor); 4223ce53722SRobert Mustacchi } 4233ce53722SRobert Mustacchi ksensor_free_dip(k); 4243ce53722SRobert Mustacchi } 4253ce53722SRobert Mustacchi 4263ce53722SRobert Mustacchi static void 4273ce53722SRobert Mustacchi ksensor_dip_unbind_cb(void *arg, dev_info_t *dip) 4283ce53722SRobert Mustacchi { 4293ce53722SRobert Mustacchi ksensor_dip_t *k = arg; 4303ce53722SRobert Mustacchi ksensor_t *sensor; 4313ce53722SRobert Mustacchi 4323ce53722SRobert Mustacchi /* 4333ce53722SRobert Mustacchi * Remove the dip and the associated sensors from global visibility. 4343ce53722SRobert Mustacchi * This will ensure that no new clients can find this; however, others 4353ce53722SRobert Mustacchi * may have extent attempts to grab it (but lost the race in an NDI 4363ce53722SRobert Mustacchi * hold). 4373ce53722SRobert Mustacchi */ 4383ce53722SRobert Mustacchi mutex_enter(&ksensor_g_mutex); 4393ce53722SRobert Mustacchi list_remove(&ksensor_dips, k); 4403ce53722SRobert Mustacchi k->ksdip_flags |= KSENSOR_DIP_F_REMOVED; 4413ce53722SRobert Mustacchi for (sensor = list_head(&k->ksdip_sensors); sensor != NULL; 4423ce53722SRobert Mustacchi sensor = list_next(&k->ksdip_sensors, sensor)) { 4433ce53722SRobert Mustacchi avl_remove(&ksensor_avl, sensor); 4443ce53722SRobert Mustacchi } 4453ce53722SRobert Mustacchi mutex_exit(&ksensor_g_mutex); 4463ce53722SRobert Mustacchi 4473ce53722SRobert Mustacchi (void) taskq_dispatch(system_taskq, ksensor_dip_unbind_taskq, k, 4483ce53722SRobert Mustacchi TQ_SLEEP); 4493ce53722SRobert Mustacchi } 4503ce53722SRobert Mustacchi 4513ce53722SRobert Mustacchi static ksensor_dip_t * 4523ce53722SRobert Mustacchi ksensor_dip_create(dev_info_t *dip) 4533ce53722SRobert Mustacchi { 4543ce53722SRobert Mustacchi ksensor_dip_t *k; 4553ce53722SRobert Mustacchi 4563ce53722SRobert Mustacchi k = kmem_zalloc(sizeof (ksensor_dip_t), KM_SLEEP); 4573ce53722SRobert Mustacchi k->ksdip_dip = dip; 4583ce53722SRobert Mustacchi k->ksdip_cb.ddiub_cb = ksensor_dip_unbind_cb; 4593ce53722SRobert Mustacchi k->ksdip_cb.ddiub_arg = k; 4603ce53722SRobert Mustacchi list_create(&k->ksdip_sensors, sizeof (ksensor_t), 4613ce53722SRobert Mustacchi offsetof(ksensor_t, ksensor_dip_list)); 4623ce53722SRobert Mustacchi e_ddi_register_unbind_callback(dip, &k->ksdip_cb); 4633ce53722SRobert Mustacchi 4643ce53722SRobert Mustacchi return (k); 4653ce53722SRobert Mustacchi } 4663ce53722SRobert Mustacchi 4673ce53722SRobert Mustacchi static ksensor_dip_t * 4683ce53722SRobert Mustacchi ksensor_dip_find(dev_info_t *dip) 4693ce53722SRobert Mustacchi { 4703ce53722SRobert Mustacchi ksensor_dip_t *k; 4713ce53722SRobert Mustacchi 4723ce53722SRobert Mustacchi ASSERT(MUTEX_HELD(&ksensor_g_mutex)); 4733ce53722SRobert Mustacchi for (k = list_head(&ksensor_dips); k != NULL; 4743ce53722SRobert Mustacchi k = list_next(&ksensor_dips, k)) { 4753ce53722SRobert Mustacchi if (dip == k->ksdip_dip) { 4763ce53722SRobert Mustacchi return (k); 4773ce53722SRobert Mustacchi } 4783ce53722SRobert Mustacchi } 4793ce53722SRobert Mustacchi 4803ce53722SRobert Mustacchi return (NULL); 4813ce53722SRobert Mustacchi } 4823ce53722SRobert Mustacchi 4833ce53722SRobert Mustacchi int 4843ce53722SRobert Mustacchi ksensor_create(dev_info_t *dip, const ksensor_ops_t *ops, void *arg, 4853ce53722SRobert Mustacchi const char *name, const char *class, id_t *idp) 4863ce53722SRobert Mustacchi { 4873ce53722SRobert Mustacchi ksensor_dip_t *ksdip; 4883ce53722SRobert Mustacchi ksensor_t *sensor; 4893ce53722SRobert Mustacchi 4903ce53722SRobert Mustacchi if (dip == NULL || ops == NULL || name == NULL || class == NULL || 4913ce53722SRobert Mustacchi idp == NULL) { 4923ce53722SRobert Mustacchi return (EINVAL); 4933ce53722SRobert Mustacchi } 4943ce53722SRobert Mustacchi 4953ce53722SRobert Mustacchi if (!DEVI_IS_ATTACHING(dip)) { 4963ce53722SRobert Mustacchi return (EAGAIN); 4973ce53722SRobert Mustacchi } 4983ce53722SRobert Mustacchi 4993ce53722SRobert Mustacchi mutex_enter(&ksensor_g_mutex); 5003ce53722SRobert Mustacchi ksdip = ksensor_dip_find(dip); 5013ce53722SRobert Mustacchi if (ksdip == NULL) { 5023ce53722SRobert Mustacchi ksdip = ksensor_dip_create(dip); 5033ce53722SRobert Mustacchi list_insert_tail(&ksensor_dips, ksdip); 5043ce53722SRobert Mustacchi } 5053ce53722SRobert Mustacchi 5063ce53722SRobert Mustacchi sensor = ksensor_search_ksdip(ksdip, name, class); 5073ce53722SRobert Mustacchi if (sensor != NULL) { 5083ce53722SRobert Mustacchi ASSERT3P(sensor->ksensor_ksdip, ==, ksdip); 5093ce53722SRobert Mustacchi if ((sensor->ksensor_flags & KSENSOR_F_VALID) != 0) { 5103ce53722SRobert Mustacchi mutex_exit(&ksensor_g_mutex); 5113ce53722SRobert Mustacchi dev_err(dip, CE_WARN, "tried to create sensor %s:%s " 5123ce53722SRobert Mustacchi "which is currently active", class, name); 5133ce53722SRobert Mustacchi return (EEXIST); 5143ce53722SRobert Mustacchi } 5153ce53722SRobert Mustacchi 5163ce53722SRobert Mustacchi sensor->ksensor_ops = ops; 5173ce53722SRobert Mustacchi sensor->ksensor_arg = arg; 5183ce53722SRobert Mustacchi } else { 5193ce53722SRobert Mustacchi sensor = kmem_zalloc(sizeof (ksensor_t), KM_SLEEP); 5203ce53722SRobert Mustacchi sensor->ksensor_ksdip = ksdip; 5213ce53722SRobert Mustacchi sensor->ksensor_name = ddi_strdup(name, KM_SLEEP); 5223ce53722SRobert Mustacchi sensor->ksensor_class = ddi_strdup(class, KM_SLEEP); 5233ce53722SRobert Mustacchi sensor->ksensor_id = id_alloc(ksensor_ids); 5243ce53722SRobert Mustacchi sensor->ksensor_ops = ops; 5253ce53722SRobert Mustacchi sensor->ksensor_arg = arg; 5263ce53722SRobert Mustacchi list_insert_tail(&ksdip->ksdip_sensors, sensor); 5273ce53722SRobert Mustacchi avl_add(&ksensor_avl, sensor); 5283ce53722SRobert Mustacchi } 5293ce53722SRobert Mustacchi 5303ce53722SRobert Mustacchi sensor->ksensor_flags |= KSENSOR_F_VALID; 5313ce53722SRobert Mustacchi 5323ce53722SRobert Mustacchi if (ksensor_cb_create != NULL) { 5333ce53722SRobert Mustacchi 5343ce53722SRobert Mustacchi if (ksensor_cb_create(sensor->ksensor_id, sensor->ksensor_class, 5353ce53722SRobert Mustacchi sensor->ksensor_name) == 0) { 5363ce53722SRobert Mustacchi sensor->ksensor_flags |= KSENSOR_F_NOTIFIED; 5373ce53722SRobert Mustacchi } 5383ce53722SRobert Mustacchi } 5393ce53722SRobert Mustacchi 5403ce53722SRobert Mustacchi *idp = sensor->ksensor_id; 5413ce53722SRobert Mustacchi mutex_exit(&ksensor_g_mutex); 5423ce53722SRobert Mustacchi 5433ce53722SRobert Mustacchi return (0); 5443ce53722SRobert Mustacchi } 5453ce53722SRobert Mustacchi 5463ce53722SRobert Mustacchi int 547*1045e13aSRobert Mustacchi ksensor_create_scalar_pcidev(dev_info_t *dip, uint_t kind, 548*1045e13aSRobert Mustacchi const ksensor_ops_t *ops, void *arg, const char *name, id_t *idp) 5493ce53722SRobert Mustacchi { 5503ce53722SRobert Mustacchi char *pci_name, *type; 551*1045e13aSRobert Mustacchi const char *class; 5523ce53722SRobert Mustacchi int *regs, ret; 5533ce53722SRobert Mustacchi uint_t nregs; 5543ce53722SRobert Mustacchi uint16_t bus, dev; 5553ce53722SRobert Mustacchi 556*1045e13aSRobert Mustacchi switch (kind) { 557*1045e13aSRobert Mustacchi case SENSOR_KIND_TEMPERATURE: 558*1045e13aSRobert Mustacchi class = "ddi_sensor:temperature:pci"; 559*1045e13aSRobert Mustacchi break; 560*1045e13aSRobert Mustacchi case SENSOR_KIND_VOLTAGE: 561*1045e13aSRobert Mustacchi class = "ddi_sensor:voltage:pci"; 562*1045e13aSRobert Mustacchi break; 563*1045e13aSRobert Mustacchi case SENSOR_KIND_CURRENT: 564*1045e13aSRobert Mustacchi class = "ddi_sensor:current:pci"; 565*1045e13aSRobert Mustacchi break; 566*1045e13aSRobert Mustacchi default: 567*1045e13aSRobert Mustacchi return (ENOTSUP); 568*1045e13aSRobert Mustacchi } 569*1045e13aSRobert Mustacchi 5703ce53722SRobert Mustacchi if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0, "device_type", 5713ce53722SRobert Mustacchi &type) != DDI_PROP_SUCCESS) { 5723ce53722SRobert Mustacchi return (EINVAL); 5733ce53722SRobert Mustacchi } 5743ce53722SRobert Mustacchi 5753ce53722SRobert Mustacchi if (strcmp(type, "pciex") != 0 && strcmp(type, "pci") != 0) { 5763ce53722SRobert Mustacchi ddi_prop_free(type); 5773ce53722SRobert Mustacchi return (EINVAL); 5783ce53722SRobert Mustacchi } 5793ce53722SRobert Mustacchi ddi_prop_free(type); 5803ce53722SRobert Mustacchi 5813ce53722SRobert Mustacchi if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0, "reg", 5823ce53722SRobert Mustacchi ®s, &nregs) != DDI_PROP_SUCCESS) { 5833ce53722SRobert Mustacchi return (EINVAL); 5843ce53722SRobert Mustacchi } 5853ce53722SRobert Mustacchi 5863ce53722SRobert Mustacchi if (nregs < 1) { 5873ce53722SRobert Mustacchi ddi_prop_free(regs); 5883ce53722SRobert Mustacchi return (EIO); 5893ce53722SRobert Mustacchi } 5903ce53722SRobert Mustacchi 5913ce53722SRobert Mustacchi bus = PCI_REG_BUS_G(regs[0]); 5923ce53722SRobert Mustacchi dev = PCI_REG_DEV_G(regs[0]); 5933ce53722SRobert Mustacchi ddi_prop_free(regs); 5943ce53722SRobert Mustacchi 5953ce53722SRobert Mustacchi pci_name = kmem_asprintf("%x.%x:%s", bus, dev, name); 5963ce53722SRobert Mustacchi 597*1045e13aSRobert Mustacchi ret = ksensor_create(dip, ops, arg, pci_name, class, idp); 5983ce53722SRobert Mustacchi strfree(pci_name); 5993ce53722SRobert Mustacchi return (ret); 6003ce53722SRobert Mustacchi } 6013ce53722SRobert Mustacchi 6023ce53722SRobert Mustacchi /* 6033ce53722SRobert Mustacchi * When a driver removes a sensor, we basically mark it as invalid. This happens 6043ce53722SRobert Mustacchi * because drivers can detach and we will need to reattach them when the sensor 6053ce53722SRobert Mustacchi * is used again. 6063ce53722SRobert Mustacchi */ 6073ce53722SRobert Mustacchi int 6083ce53722SRobert Mustacchi ksensor_remove(dev_info_t *dip, id_t id) 6093ce53722SRobert Mustacchi { 6103ce53722SRobert Mustacchi ksensor_dip_t *kdip; 6113ce53722SRobert Mustacchi ksensor_t *sensor; 6123ce53722SRobert Mustacchi 6133ce53722SRobert Mustacchi if (!DEVI_IS_ATTACHING(dip) && !DEVI_IS_DETACHING(dip)) { 6143ce53722SRobert Mustacchi return (EAGAIN); 6153ce53722SRobert Mustacchi } 6163ce53722SRobert Mustacchi 6173ce53722SRobert Mustacchi mutex_enter(&ksensor_g_mutex); 6183ce53722SRobert Mustacchi kdip = ksensor_dip_find(dip); 6193ce53722SRobert Mustacchi if (kdip == NULL) { 6203ce53722SRobert Mustacchi mutex_exit(&ksensor_g_mutex); 6213ce53722SRobert Mustacchi return (ENOENT); 6223ce53722SRobert Mustacchi } 6233ce53722SRobert Mustacchi 6243ce53722SRobert Mustacchi for (sensor = list_head(&kdip->ksdip_sensors); sensor != NULL; 6253ce53722SRobert Mustacchi sensor = list_next(&kdip->ksdip_sensors, sensor)) { 6263ce53722SRobert Mustacchi if (sensor->ksensor_id == id || id == KSENSOR_ALL_IDS) { 6273ce53722SRobert Mustacchi mutex_enter(&sensor->ksensor_mutex); 6283ce53722SRobert Mustacchi sensor->ksensor_flags &= ~KSENSOR_F_VALID; 6293ce53722SRobert Mustacchi sensor->ksensor_ops = NULL; 6303ce53722SRobert Mustacchi sensor->ksensor_arg = NULL; 6313ce53722SRobert Mustacchi mutex_exit(&sensor->ksensor_mutex); 6323ce53722SRobert Mustacchi } 6333ce53722SRobert Mustacchi } 6343ce53722SRobert Mustacchi mutex_exit(&ksensor_g_mutex); 6353ce53722SRobert Mustacchi return (0); 6363ce53722SRobert Mustacchi } 6373ce53722SRobert Mustacchi 6383ce53722SRobert Mustacchi static void 6393ce53722SRobert Mustacchi ksensor_release(ksensor_t *sensor) 6403ce53722SRobert Mustacchi { 6413ce53722SRobert Mustacchi int circ; 6423ce53722SRobert Mustacchi dev_info_t *pdip; 6433ce53722SRobert Mustacchi 6443ce53722SRobert Mustacchi ddi_release_devi(sensor->ksensor_ksdip->ksdip_dip); 6453ce53722SRobert Mustacchi 6463ce53722SRobert Mustacchi mutex_enter(&sensor->ksensor_mutex); 6473ce53722SRobert Mustacchi sensor->ksensor_flags &= ~KSENSOR_F_BUSY; 6483ce53722SRobert Mustacchi cv_broadcast(&sensor->ksensor_cv); 6493ce53722SRobert Mustacchi mutex_exit(&sensor->ksensor_mutex); 6503ce53722SRobert Mustacchi } 6513ce53722SRobert Mustacchi 6523ce53722SRobert Mustacchi static int 6533ce53722SRobert Mustacchi ksensor_hold_by_id(id_t id, ksensor_t **outp) 6543ce53722SRobert Mustacchi { 6553ce53722SRobert Mustacchi int circ; 6563ce53722SRobert Mustacchi ksensor_t *sensor; 6573ce53722SRobert Mustacchi dev_info_t *pdip; 6583ce53722SRobert Mustacchi 6593ce53722SRobert Mustacchi restart: 6603ce53722SRobert Mustacchi mutex_enter(&ksensor_g_mutex); 6613ce53722SRobert Mustacchi sensor = ksensor_find_by_id(id); 6623ce53722SRobert Mustacchi if (sensor == NULL) { 6633ce53722SRobert Mustacchi mutex_exit(&ksensor_g_mutex); 6643ce53722SRobert Mustacchi *outp = NULL; 6653ce53722SRobert Mustacchi return (ESTALE); 6663ce53722SRobert Mustacchi } 6673ce53722SRobert Mustacchi 6683ce53722SRobert Mustacchi if ((sensor->ksensor_ksdip->ksdip_flags & KSENSOR_DIP_F_REMOVED) != 0) { 6693ce53722SRobert Mustacchi mutex_exit(&ksensor_g_mutex); 6703ce53722SRobert Mustacchi *outp = NULL; 6713ce53722SRobert Mustacchi return (ESTALE); 6723ce53722SRobert Mustacchi } 6733ce53722SRobert Mustacchi 6743ce53722SRobert Mustacchi mutex_enter(&sensor->ksensor_mutex); 6753ce53722SRobert Mustacchi if ((sensor->ksensor_flags & KSENSOR_F_BUSY) != 0) { 6763ce53722SRobert Mustacchi mutex_exit(&ksensor_g_mutex); 6773ce53722SRobert Mustacchi sensor->ksensor_nwaiters++; 6783ce53722SRobert Mustacchi while ((sensor->ksensor_flags & KSENSOR_F_BUSY) != 0) { 6793ce53722SRobert Mustacchi int cv = cv_wait_sig(&sensor->ksensor_cv, 6803ce53722SRobert Mustacchi &sensor->ksensor_mutex); 6813ce53722SRobert Mustacchi if (cv == 0) { 6823ce53722SRobert Mustacchi sensor->ksensor_nwaiters--; 6833ce53722SRobert Mustacchi cv_broadcast(&sensor->ksensor_cv); 6843ce53722SRobert Mustacchi mutex_exit(&sensor->ksensor_mutex); 6853ce53722SRobert Mustacchi *outp = NULL; 6863ce53722SRobert Mustacchi return (EINTR); 6873ce53722SRobert Mustacchi } 6883ce53722SRobert Mustacchi } 6893ce53722SRobert Mustacchi sensor->ksensor_nwaiters--; 6903ce53722SRobert Mustacchi cv_broadcast(&sensor->ksensor_cv); 6913ce53722SRobert Mustacchi mutex_exit(&sensor->ksensor_mutex); 6923ce53722SRobert Mustacchi goto restart; 6933ce53722SRobert Mustacchi } 6943ce53722SRobert Mustacchi 6953ce53722SRobert Mustacchi /* 6963ce53722SRobert Mustacchi * We have obtained ownership of the sensor. At this point, we should 6973ce53722SRobert Mustacchi * check to see if it's valid or not. 6983ce53722SRobert Mustacchi */ 6993ce53722SRobert Mustacchi sensor->ksensor_flags |= KSENSOR_F_BUSY; 7003ce53722SRobert Mustacchi pdip = ddi_get_parent(sensor->ksensor_ksdip->ksdip_dip); 7013ce53722SRobert Mustacchi mutex_exit(&sensor->ksensor_mutex); 7023ce53722SRobert Mustacchi mutex_exit(&ksensor_g_mutex); 7033ce53722SRobert Mustacchi 7043ce53722SRobert Mustacchi /* 7053ce53722SRobert Mustacchi * Grab a reference on the device node to ensure that it won't go away. 7063ce53722SRobert Mustacchi */ 7073ce53722SRobert Mustacchi ndi_devi_enter(pdip, &circ); 7083ce53722SRobert Mustacchi e_ddi_hold_devi(sensor->ksensor_ksdip->ksdip_dip); 7093ce53722SRobert Mustacchi ndi_devi_exit(pdip, circ); 7103ce53722SRobert Mustacchi 7113ce53722SRobert Mustacchi /* 7123ce53722SRobert Mustacchi * Now that we have an NDI hold, check if it's valid or not. It may have 7133ce53722SRobert Mustacchi * become invalid while we were waiting due to a race. 7143ce53722SRobert Mustacchi */ 7153ce53722SRobert Mustacchi mutex_enter(&ksensor_g_mutex); 7163ce53722SRobert Mustacchi if ((sensor->ksensor_ksdip->ksdip_flags & KSENSOR_DIP_F_REMOVED) != 0) { 7173ce53722SRobert Mustacchi mutex_exit(&ksensor_g_mutex); 7183ce53722SRobert Mustacchi ksensor_release(sensor); 7193ce53722SRobert Mustacchi return (ESTALE); 7203ce53722SRobert Mustacchi } 7213ce53722SRobert Mustacchi 7223ce53722SRobert Mustacchi mutex_enter(&sensor->ksensor_mutex); 7233ce53722SRobert Mustacchi if ((sensor->ksensor_flags & KSENSOR_F_VALID) == 0) { 7243ce53722SRobert Mustacchi mutex_exit(&sensor->ksensor_mutex); 7253ce53722SRobert Mustacchi mutex_exit(&ksensor_g_mutex); 7263ce53722SRobert Mustacchi (void) ndi_devi_config(pdip, NDI_NO_EVENT); 7273ce53722SRobert Mustacchi mutex_enter(&ksensor_g_mutex); 7283ce53722SRobert Mustacchi mutex_enter(&sensor->ksensor_mutex); 7293ce53722SRobert Mustacchi 7303ce53722SRobert Mustacchi /* 7313ce53722SRobert Mustacchi * If we attempted to reattach it and it isn't now valid, fail 7323ce53722SRobert Mustacchi * this request. 7333ce53722SRobert Mustacchi */ 7343ce53722SRobert Mustacchi if ((sensor->ksensor_ksdip->ksdip_flags & 7353ce53722SRobert Mustacchi KSENSOR_DIP_F_REMOVED) != 0 || 7363ce53722SRobert Mustacchi (sensor->ksensor_flags & KSENSOR_F_VALID) == 0) { 7373ce53722SRobert Mustacchi mutex_exit(&sensor->ksensor_mutex); 7383ce53722SRobert Mustacchi mutex_exit(&ksensor_g_mutex); 7393ce53722SRobert Mustacchi ksensor_release(sensor); 7403ce53722SRobert Mustacchi return (ESTALE); 7413ce53722SRobert Mustacchi } 7423ce53722SRobert Mustacchi } 7433ce53722SRobert Mustacchi mutex_exit(&sensor->ksensor_mutex); 7443ce53722SRobert Mustacchi mutex_exit(&ksensor_g_mutex); 7453ce53722SRobert Mustacchi *outp = sensor; 7463ce53722SRobert Mustacchi 7473ce53722SRobert Mustacchi return (0); 7483ce53722SRobert Mustacchi } 7493ce53722SRobert Mustacchi 7503ce53722SRobert Mustacchi int 7513ce53722SRobert Mustacchi ksensor_op_kind(id_t id, sensor_ioctl_kind_t *kind) 7523ce53722SRobert Mustacchi { 7533ce53722SRobert Mustacchi int ret; 7543ce53722SRobert Mustacchi ksensor_t *sensor; 7553ce53722SRobert Mustacchi 7563ce53722SRobert Mustacchi if ((ret = ksensor_hold_by_id(id, &sensor)) != 0) { 7573ce53722SRobert Mustacchi return (ret); 7583ce53722SRobert Mustacchi } 7593ce53722SRobert Mustacchi 7603ce53722SRobert Mustacchi ret = sensor->ksensor_ops->kso_kind(sensor->ksensor_arg, kind); 7613ce53722SRobert Mustacchi ksensor_release(sensor); 7623ce53722SRobert Mustacchi 7633ce53722SRobert Mustacchi return (ret); 7643ce53722SRobert Mustacchi } 7653ce53722SRobert Mustacchi 7663ce53722SRobert Mustacchi int 767*1045e13aSRobert Mustacchi ksensor_op_scalar(id_t id, sensor_ioctl_scalar_t *scalar) 7683ce53722SRobert Mustacchi { 7693ce53722SRobert Mustacchi int ret; 7703ce53722SRobert Mustacchi ksensor_t *sensor; 7713ce53722SRobert Mustacchi 7723ce53722SRobert Mustacchi if ((ret = ksensor_hold_by_id(id, &sensor)) != 0) { 7733ce53722SRobert Mustacchi return (ret); 7743ce53722SRobert Mustacchi } 7753ce53722SRobert Mustacchi 776*1045e13aSRobert Mustacchi ret = sensor->ksensor_ops->kso_scalar(sensor->ksensor_arg, scalar); 7773ce53722SRobert Mustacchi ksensor_release(sensor); 7783ce53722SRobert Mustacchi 7793ce53722SRobert Mustacchi return (ret); 7803ce53722SRobert Mustacchi } 7813ce53722SRobert Mustacchi 7823ce53722SRobert Mustacchi void 7833ce53722SRobert Mustacchi ksensor_unregister(dev_info_t *reg_dip) 7843ce53722SRobert Mustacchi { 7853ce53722SRobert Mustacchi ksensor_t *sensor; 7863ce53722SRobert Mustacchi 7873ce53722SRobert Mustacchi mutex_enter(&ksensor_g_mutex); 7883ce53722SRobert Mustacchi if (ksensor_cb_dip != reg_dip) { 7893ce53722SRobert Mustacchi dev_err(reg_dip, CE_PANIC, "asked to unregister illegal dip"); 7903ce53722SRobert Mustacchi } 7913ce53722SRobert Mustacchi 7923ce53722SRobert Mustacchi for (sensor = avl_first(&ksensor_avl); sensor != NULL; sensor = 7933ce53722SRobert Mustacchi AVL_NEXT(&ksensor_avl, sensor)) { 7943ce53722SRobert Mustacchi mutex_enter(&sensor->ksensor_mutex); 7953ce53722SRobert Mustacchi sensor->ksensor_flags &= ~KSENSOR_F_NOTIFIED; 7963ce53722SRobert Mustacchi mutex_exit(&sensor->ksensor_mutex); 7973ce53722SRobert Mustacchi } 7983ce53722SRobert Mustacchi 7993ce53722SRobert Mustacchi ksensor_cb_dip = NULL; 8003ce53722SRobert Mustacchi ksensor_cb_create = NULL; 8013ce53722SRobert Mustacchi ksensor_cb_remove = NULL; 8023ce53722SRobert Mustacchi mutex_exit(&ksensor_g_mutex); 8033ce53722SRobert Mustacchi } 8043ce53722SRobert Mustacchi 8053ce53722SRobert Mustacchi int 8063ce53722SRobert Mustacchi ksensor_register(dev_info_t *reg_dip, ksensor_create_f create, 8073ce53722SRobert Mustacchi ksensor_remove_f remove) 8083ce53722SRobert Mustacchi { 8093ce53722SRobert Mustacchi ksensor_t *sensor; 8103ce53722SRobert Mustacchi 8113ce53722SRobert Mustacchi mutex_enter(&ksensor_g_mutex); 8123ce53722SRobert Mustacchi if (ksensor_cb_dip != NULL) { 8133ce53722SRobert Mustacchi dev_err(reg_dip, CE_WARN, "kernel sensors are already " 8143ce53722SRobert Mustacchi "registered"); 8153ce53722SRobert Mustacchi mutex_exit(&ksensor_g_mutex); 8163ce53722SRobert Mustacchi return (EEXIST); 8173ce53722SRobert Mustacchi } 8183ce53722SRobert Mustacchi 8193ce53722SRobert Mustacchi ksensor_cb_dip = reg_dip; 8203ce53722SRobert Mustacchi ksensor_cb_create = create; 8213ce53722SRobert Mustacchi ksensor_cb_remove = remove; 8223ce53722SRobert Mustacchi 8233ce53722SRobert Mustacchi for (sensor = avl_first(&ksensor_avl); sensor != NULL; sensor = 8243ce53722SRobert Mustacchi AVL_NEXT(&ksensor_avl, sensor)) { 8253ce53722SRobert Mustacchi mutex_enter(&sensor->ksensor_mutex); 8263ce53722SRobert Mustacchi ASSERT0(sensor->ksensor_flags & KSENSOR_F_NOTIFIED); 8273ce53722SRobert Mustacchi 8283ce53722SRobert Mustacchi if (ksensor_cb_create(sensor->ksensor_id, sensor->ksensor_class, 8293ce53722SRobert Mustacchi sensor->ksensor_name) == 0) { 8303ce53722SRobert Mustacchi sensor->ksensor_flags |= KSENSOR_F_NOTIFIED; 8313ce53722SRobert Mustacchi } 8323ce53722SRobert Mustacchi 8333ce53722SRobert Mustacchi mutex_exit(&sensor->ksensor_mutex); 8343ce53722SRobert Mustacchi } 8353ce53722SRobert Mustacchi 8363ce53722SRobert Mustacchi mutex_exit(&ksensor_g_mutex); 8373ce53722SRobert Mustacchi 8383ce53722SRobert Mustacchi return (0); 8393ce53722SRobert Mustacchi } 8403ce53722SRobert Mustacchi 8413ce53722SRobert Mustacchi int 8423ce53722SRobert Mustacchi ksensor_kind_temperature(void *unused, sensor_ioctl_kind_t *k) 8433ce53722SRobert Mustacchi { 8443ce53722SRobert Mustacchi k->sik_kind = SENSOR_KIND_TEMPERATURE; 8453ce53722SRobert Mustacchi return (0); 8463ce53722SRobert Mustacchi } 8473ce53722SRobert Mustacchi 848*1045e13aSRobert Mustacchi int 849*1045e13aSRobert Mustacchi ksensor_kind_current(void *unused, sensor_ioctl_kind_t *k) 850*1045e13aSRobert Mustacchi { 851*1045e13aSRobert Mustacchi k->sik_kind = SENSOR_KIND_CURRENT; 852*1045e13aSRobert Mustacchi return (0); 853*1045e13aSRobert Mustacchi } 854*1045e13aSRobert Mustacchi 855*1045e13aSRobert Mustacchi int 856*1045e13aSRobert Mustacchi ksensor_kind_voltage(void *unused, sensor_ioctl_kind_t *k) 857*1045e13aSRobert Mustacchi { 858*1045e13aSRobert Mustacchi k->sik_kind = SENSOR_KIND_VOLTAGE; 859*1045e13aSRobert Mustacchi return (0); 860*1045e13aSRobert Mustacchi } 861*1045e13aSRobert Mustacchi 8623ce53722SRobert Mustacchi void 8633ce53722SRobert Mustacchi ksensor_init(void) 8643ce53722SRobert Mustacchi { 8653ce53722SRobert Mustacchi mutex_init(&ksensor_g_mutex, NULL, MUTEX_DRIVER, NULL); 8663ce53722SRobert Mustacchi list_create(&ksensor_dips, sizeof (ksensor_dip_t), 8673ce53722SRobert Mustacchi offsetof(ksensor_dip_t, ksdip_link)); 8683ce53722SRobert Mustacchi ksensor_ids = id_space_create("ksensor", 1, L_MAXMIN32); 8693ce53722SRobert Mustacchi avl_create(&ksensor_avl, ksensor_avl_compare, sizeof (ksensor_t), 8703ce53722SRobert Mustacchi offsetof(ksensor_t, ksensor_id_avl)); 8713ce53722SRobert Mustacchi } 872