cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

dock.c (16665B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  dock.c - ACPI dock station driver
      4 *
      5 *  Copyright (C) 2006, 2014, Intel Corp.
      6 *  Author: Kristen Carlson Accardi <kristen.c.accardi@intel.com>
      7 *          Rafael J. Wysocki <rafael.j.wysocki@intel.com>
      8 */
      9
     10#include <linux/kernel.h>
     11#include <linux/moduleparam.h>
     12#include <linux/slab.h>
     13#include <linux/init.h>
     14#include <linux/types.h>
     15#include <linux/notifier.h>
     16#include <linux/platform_device.h>
     17#include <linux/jiffies.h>
     18#include <linux/stddef.h>
     19#include <linux/acpi.h>
     20
     21#include "internal.h"
     22
     23static bool immediate_undock = 1;
     24module_param(immediate_undock, bool, 0644);
     25MODULE_PARM_DESC(immediate_undock, "1 (default) will cause the driver to "
     26	"undock immediately when the undock button is pressed, 0 will cause"
     27	" the driver to wait for userspace to write the undock sysfs file "
     28	" before undocking");
     29
     30struct dock_station {
     31	acpi_handle handle;
     32	unsigned long last_dock_time;
     33	u32 flags;
     34	struct list_head dependent_devices;
     35
     36	struct list_head sibling;
     37	struct platform_device *dock_device;
     38};
     39static LIST_HEAD(dock_stations);
     40static int dock_station_count;
     41
     42struct dock_dependent_device {
     43	struct list_head list;
     44	struct acpi_device *adev;
     45};
     46
     47#define DOCK_DOCKING	0x00000001
     48#define DOCK_UNDOCKING  0x00000002
     49#define DOCK_IS_DOCK	0x00000010
     50#define DOCK_IS_ATA	0x00000020
     51#define DOCK_IS_BAT	0x00000040
     52#define DOCK_EVENT	3
     53#define UNDOCK_EVENT	2
     54
     55enum dock_callback_type {
     56	DOCK_CALL_HANDLER,
     57	DOCK_CALL_FIXUP,
     58	DOCK_CALL_UEVENT,
     59};
     60
     61/*****************************************************************************
     62 *                         Dock Dependent device functions                   *
     63 *****************************************************************************/
     64/**
     65 * add_dock_dependent_device - associate a device with the dock station
     66 * @ds: Dock station.
     67 * @adev: Dependent ACPI device object.
     68 *
     69 * Add the dependent device to the dock's dependent device list.
     70 */
     71static int add_dock_dependent_device(struct dock_station *ds,
     72				     struct acpi_device *adev)
     73{
     74	struct dock_dependent_device *dd;
     75
     76	dd = kzalloc(sizeof(*dd), GFP_KERNEL);
     77	if (!dd)
     78		return -ENOMEM;
     79
     80	dd->adev = adev;
     81	INIT_LIST_HEAD(&dd->list);
     82	list_add_tail(&dd->list, &ds->dependent_devices);
     83
     84	return 0;
     85}
     86
     87static void dock_hotplug_event(struct dock_dependent_device *dd, u32 event,
     88			       enum dock_callback_type cb_type)
     89{
     90	struct acpi_device *adev = dd->adev;
     91
     92	acpi_lock_hp_context();
     93
     94	if (!adev->hp)
     95		goto out;
     96
     97	if (cb_type == DOCK_CALL_FIXUP) {
     98		void (*fixup)(struct acpi_device *);
     99
    100		fixup = adev->hp->fixup;
    101		if (fixup) {
    102			acpi_unlock_hp_context();
    103			fixup(adev);
    104			return;
    105		}
    106	} else if (cb_type == DOCK_CALL_UEVENT) {
    107		void (*uevent)(struct acpi_device *, u32);
    108
    109		uevent = adev->hp->uevent;
    110		if (uevent) {
    111			acpi_unlock_hp_context();
    112			uevent(adev, event);
    113			return;
    114		}
    115	} else {
    116		int (*notify)(struct acpi_device *, u32);
    117
    118		notify = adev->hp->notify;
    119		if (notify) {
    120			acpi_unlock_hp_context();
    121			notify(adev, event);
    122			return;
    123		}
    124	}
    125
    126 out:
    127	acpi_unlock_hp_context();
    128}
    129
    130static struct dock_station *find_dock_station(acpi_handle handle)
    131{
    132	struct dock_station *ds;
    133
    134	list_for_each_entry(ds, &dock_stations, sibling)
    135		if (ds->handle == handle)
    136			return ds;
    137
    138	return NULL;
    139}
    140
    141/**
    142 * find_dock_dependent_device - get a device dependent on this dock
    143 * @ds: the dock station
    144 * @adev: ACPI device object to find.
    145 *
    146 * iterate over the dependent device list for this dock.  If the
    147 * dependent device matches the handle, return.
    148 */
    149static struct dock_dependent_device *
    150find_dock_dependent_device(struct dock_station *ds, struct acpi_device *adev)
    151{
    152	struct dock_dependent_device *dd;
    153
    154	list_for_each_entry(dd, &ds->dependent_devices, list)
    155		if (adev == dd->adev)
    156			return dd;
    157
    158	return NULL;
    159}
    160
    161void register_dock_dependent_device(struct acpi_device *adev,
    162				    acpi_handle dshandle)
    163{
    164	struct dock_station *ds = find_dock_station(dshandle);
    165
    166	if (ds && !find_dock_dependent_device(ds, adev))
    167		add_dock_dependent_device(ds, adev);
    168}
    169
    170/*****************************************************************************
    171 *                         Dock functions                                    *
    172 *****************************************************************************/
    173
    174/**
    175 * is_dock_device - see if a device is on a dock station
    176 * @adev: ACPI device object to check.
    177 *
    178 * If this device is either the dock station itself,
    179 * or is a device dependent on the dock station, then it
    180 * is a dock device
    181 */
    182int is_dock_device(struct acpi_device *adev)
    183{
    184	struct dock_station *dock_station;
    185
    186	if (!dock_station_count)
    187		return 0;
    188
    189	if (acpi_dock_match(adev->handle))
    190		return 1;
    191
    192	list_for_each_entry(dock_station, &dock_stations, sibling)
    193		if (find_dock_dependent_device(dock_station, adev))
    194			return 1;
    195
    196	return 0;
    197}
    198EXPORT_SYMBOL_GPL(is_dock_device);
    199
    200/**
    201 * dock_present - see if the dock station is present.
    202 * @ds: the dock station
    203 *
    204 * execute the _STA method.  note that present does not
    205 * imply that we are docked.
    206 */
    207static int dock_present(struct dock_station *ds)
    208{
    209	unsigned long long sta;
    210	acpi_status status;
    211
    212	if (ds) {
    213		status = acpi_evaluate_integer(ds->handle, "_STA", NULL, &sta);
    214		if (ACPI_SUCCESS(status) && sta)
    215			return 1;
    216	}
    217	return 0;
    218}
    219
    220/**
    221 * hot_remove_dock_devices - Remove dock station devices.
    222 * @ds: Dock station.
    223 */
    224static void hot_remove_dock_devices(struct dock_station *ds)
    225{
    226	struct dock_dependent_device *dd;
    227
    228	/*
    229	 * Walk the list in reverse order so that devices that have been added
    230	 * last are removed first (in case there are some indirect dependencies
    231	 * between them).
    232	 */
    233	list_for_each_entry_reverse(dd, &ds->dependent_devices, list)
    234		dock_hotplug_event(dd, ACPI_NOTIFY_EJECT_REQUEST,
    235				   DOCK_CALL_HANDLER);
    236
    237	list_for_each_entry_reverse(dd, &ds->dependent_devices, list)
    238		acpi_bus_trim(dd->adev);
    239}
    240
    241/**
    242 * hotplug_dock_devices - Insert devices on a dock station.
    243 * @ds: the dock station
    244 * @event: either bus check or device check request
    245 *
    246 * Some devices on the dock station need to have drivers called
    247 * to perform hotplug operations after a dock event has occurred.
    248 * Traverse the list of dock devices that have registered a
    249 * hotplug handler, and call the handler.
    250 */
    251static void hotplug_dock_devices(struct dock_station *ds, u32 event)
    252{
    253	struct dock_dependent_device *dd;
    254
    255	/* Call driver specific post-dock fixups. */
    256	list_for_each_entry(dd, &ds->dependent_devices, list)
    257		dock_hotplug_event(dd, event, DOCK_CALL_FIXUP);
    258
    259	/* Call driver specific hotplug functions. */
    260	list_for_each_entry(dd, &ds->dependent_devices, list)
    261		dock_hotplug_event(dd, event, DOCK_CALL_HANDLER);
    262
    263	/*
    264	 * Check if all devices have been enumerated already.  If not, run
    265	 * acpi_bus_scan() for them and that will cause scan handlers to be
    266	 * attached to device objects or acpi_drivers to be stopped/started if
    267	 * they are present.
    268	 */
    269	list_for_each_entry(dd, &ds->dependent_devices, list) {
    270		struct acpi_device *adev = dd->adev;
    271
    272		if (!acpi_device_enumerated(adev)) {
    273			int ret = acpi_bus_scan(adev->handle);
    274
    275			if (ret)
    276				dev_dbg(&adev->dev, "scan error %d\n", -ret);
    277		}
    278	}
    279}
    280
    281static void dock_event(struct dock_station *ds, u32 event, int num)
    282{
    283	struct device *dev = &ds->dock_device->dev;
    284	char event_string[13];
    285	char *envp[] = { event_string, NULL };
    286	struct dock_dependent_device *dd;
    287
    288	if (num == UNDOCK_EVENT)
    289		sprintf(event_string, "EVENT=undock");
    290	else
    291		sprintf(event_string, "EVENT=dock");
    292
    293	/*
    294	 * Indicate that the status of the dock station has
    295	 * changed.
    296	 */
    297	if (num == DOCK_EVENT)
    298		kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
    299
    300	list_for_each_entry(dd, &ds->dependent_devices, list)
    301		dock_hotplug_event(dd, event, DOCK_CALL_UEVENT);
    302
    303	if (num != DOCK_EVENT)
    304		kobject_uevent_env(&dev->kobj, KOBJ_CHANGE, envp);
    305}
    306
    307/**
    308 * handle_dock - handle a dock event
    309 * @ds: the dock station
    310 * @dock: to dock, or undock - that is the question
    311 *
    312 * Execute the _DCK method in response to an acpi event
    313 */
    314static void handle_dock(struct dock_station *ds, int dock)
    315{
    316	acpi_status status;
    317	struct acpi_object_list arg_list;
    318	union acpi_object arg;
    319	unsigned long long value;
    320
    321	acpi_handle_info(ds->handle, "%s\n", dock ? "docking" : "undocking");
    322
    323	/* _DCK method has one argument */
    324	arg_list.count = 1;
    325	arg_list.pointer = &arg;
    326	arg.type = ACPI_TYPE_INTEGER;
    327	arg.integer.value = dock;
    328	status = acpi_evaluate_integer(ds->handle, "_DCK", &arg_list, &value);
    329	if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
    330		acpi_handle_err(ds->handle, "Failed to execute _DCK (0x%x)\n",
    331				status);
    332}
    333
    334static inline void dock(struct dock_station *ds)
    335{
    336	handle_dock(ds, 1);
    337}
    338
    339static inline void undock(struct dock_station *ds)
    340{
    341	handle_dock(ds, 0);
    342}
    343
    344static inline void begin_dock(struct dock_station *ds)
    345{
    346	ds->flags |= DOCK_DOCKING;
    347}
    348
    349static inline void complete_dock(struct dock_station *ds)
    350{
    351	ds->flags &= ~(DOCK_DOCKING);
    352	ds->last_dock_time = jiffies;
    353}
    354
    355static inline void begin_undock(struct dock_station *ds)
    356{
    357	ds->flags |= DOCK_UNDOCKING;
    358}
    359
    360static inline void complete_undock(struct dock_station *ds)
    361{
    362	ds->flags &= ~(DOCK_UNDOCKING);
    363}
    364
    365/**
    366 * dock_in_progress - see if we are in the middle of handling a dock event
    367 * @ds: the dock station
    368 *
    369 * Sometimes while docking, false dock events can be sent to the driver
    370 * because good connections aren't made or some other reason.  Ignore these
    371 * if we are in the middle of doing something.
    372 */
    373static int dock_in_progress(struct dock_station *ds)
    374{
    375	if ((ds->flags & DOCK_DOCKING) ||
    376	    time_before(jiffies, (ds->last_dock_time + HZ)))
    377		return 1;
    378	return 0;
    379}
    380
    381/**
    382 * handle_eject_request - handle an undock request checking for error conditions
    383 *
    384 * Check to make sure the dock device is still present, then undock and
    385 * hotremove all the devices that may need removing.
    386 */
    387static int handle_eject_request(struct dock_station *ds, u32 event)
    388{
    389	if (dock_in_progress(ds))
    390		return -EBUSY;
    391
    392	/*
    393	 * here we need to generate the undock
    394	 * event prior to actually doing the undock
    395	 * so that the device struct still exists.
    396	 * Also, even send the dock event if the
    397	 * device is not present anymore
    398	 */
    399	dock_event(ds, event, UNDOCK_EVENT);
    400
    401	hot_remove_dock_devices(ds);
    402	undock(ds);
    403	acpi_evaluate_lck(ds->handle, 0);
    404	acpi_evaluate_ej0(ds->handle);
    405	if (dock_present(ds)) {
    406		acpi_handle_err(ds->handle, "Unable to undock!\n");
    407		return -EBUSY;
    408	}
    409	complete_undock(ds);
    410	return 0;
    411}
    412
    413/**
    414 * dock_notify - Handle ACPI dock notification.
    415 * @adev: Dock station's ACPI device object.
    416 * @event: Event code.
    417 *
    418 * If we are notified to dock, then check to see if the dock is
    419 * present and then dock.  Notify all drivers of the dock event,
    420 * and then hotplug and devices that may need hotplugging.
    421 */
    422int dock_notify(struct acpi_device *adev, u32 event)
    423{
    424	acpi_handle handle = adev->handle;
    425	struct dock_station *ds = find_dock_station(handle);
    426	int surprise_removal = 0;
    427
    428	if (!ds)
    429		return -ENODEV;
    430
    431	/*
    432	 * According to acpi spec 3.0a, if a DEVICE_CHECK notification
    433	 * is sent and _DCK is present, it is assumed to mean an undock
    434	 * request.
    435	 */
    436	if ((ds->flags & DOCK_IS_DOCK) && event == ACPI_NOTIFY_DEVICE_CHECK)
    437		event = ACPI_NOTIFY_EJECT_REQUEST;
    438
    439	/*
    440	 * dock station: BUS_CHECK - docked or surprise removal
    441	 *		 DEVICE_CHECK - undocked
    442	 * other device: BUS_CHECK/DEVICE_CHECK - added or surprise removal
    443	 *
    444	 * To simplify event handling, dock dependent device handler always
    445	 * get ACPI_NOTIFY_BUS_CHECK/ACPI_NOTIFY_DEVICE_CHECK for add and
    446	 * ACPI_NOTIFY_EJECT_REQUEST for removal
    447	 */
    448	switch (event) {
    449	case ACPI_NOTIFY_BUS_CHECK:
    450	case ACPI_NOTIFY_DEVICE_CHECK:
    451		if (!dock_in_progress(ds) && !acpi_device_enumerated(adev)) {
    452			begin_dock(ds);
    453			dock(ds);
    454			if (!dock_present(ds)) {
    455				acpi_handle_err(handle, "Unable to dock!\n");
    456				complete_dock(ds);
    457				break;
    458			}
    459			hotplug_dock_devices(ds, event);
    460			complete_dock(ds);
    461			dock_event(ds, event, DOCK_EVENT);
    462			acpi_evaluate_lck(ds->handle, 1);
    463			acpi_update_all_gpes();
    464			break;
    465		}
    466		if (dock_present(ds) || dock_in_progress(ds))
    467			break;
    468		/* This is a surprise removal */
    469		surprise_removal = 1;
    470		event = ACPI_NOTIFY_EJECT_REQUEST;
    471		/* Fall back */
    472		fallthrough;
    473	case ACPI_NOTIFY_EJECT_REQUEST:
    474		begin_undock(ds);
    475		if ((immediate_undock && !(ds->flags & DOCK_IS_ATA))
    476		   || surprise_removal)
    477			handle_eject_request(ds, event);
    478		else
    479			dock_event(ds, event, UNDOCK_EVENT);
    480		break;
    481	}
    482	return 0;
    483}
    484
    485/*
    486 * show_docked - read method for "docked" file in sysfs
    487 */
    488static ssize_t docked_show(struct device *dev,
    489			   struct device_attribute *attr, char *buf)
    490{
    491	struct dock_station *dock_station = dev->platform_data;
    492	struct acpi_device *adev = acpi_fetch_acpi_dev(dock_station->handle);
    493
    494	return sysfs_emit(buf, "%u\n", acpi_device_enumerated(adev));
    495}
    496static DEVICE_ATTR_RO(docked);
    497
    498/*
    499 * show_flags - read method for flags file in sysfs
    500 */
    501static ssize_t flags_show(struct device *dev,
    502			  struct device_attribute *attr, char *buf)
    503{
    504	struct dock_station *dock_station = dev->platform_data;
    505
    506	return sysfs_emit(buf, "%d\n", dock_station->flags);
    507
    508}
    509static DEVICE_ATTR_RO(flags);
    510
    511/*
    512 * write_undock - write method for "undock" file in sysfs
    513 */
    514static ssize_t undock_store(struct device *dev, struct device_attribute *attr,
    515			    const char *buf, size_t count)
    516{
    517	int ret;
    518	struct dock_station *dock_station = dev->platform_data;
    519
    520	if (!count)
    521		return -EINVAL;
    522
    523	acpi_scan_lock_acquire();
    524	begin_undock(dock_station);
    525	ret = handle_eject_request(dock_station, ACPI_NOTIFY_EJECT_REQUEST);
    526	acpi_scan_lock_release();
    527	return ret ? ret : count;
    528}
    529static DEVICE_ATTR_WO(undock);
    530
    531/*
    532 * show_dock_uid - read method for "uid" file in sysfs
    533 */
    534static ssize_t uid_show(struct device *dev,
    535			struct device_attribute *attr, char *buf)
    536{
    537	unsigned long long lbuf;
    538	struct dock_station *dock_station = dev->platform_data;
    539
    540	acpi_status status = acpi_evaluate_integer(dock_station->handle,
    541					"_UID", NULL, &lbuf);
    542	if (ACPI_FAILURE(status))
    543		return 0;
    544
    545	return sysfs_emit(buf, "%llx\n", lbuf);
    546}
    547static DEVICE_ATTR_RO(uid);
    548
    549static ssize_t type_show(struct device *dev,
    550			 struct device_attribute *attr, char *buf)
    551{
    552	struct dock_station *dock_station = dev->platform_data;
    553	char *type;
    554
    555	if (dock_station->flags & DOCK_IS_DOCK)
    556		type = "dock_station";
    557	else if (dock_station->flags & DOCK_IS_ATA)
    558		type = "ata_bay";
    559	else if (dock_station->flags & DOCK_IS_BAT)
    560		type = "battery_bay";
    561	else
    562		type = "unknown";
    563
    564	return sysfs_emit(buf, "%s\n", type);
    565}
    566static DEVICE_ATTR_RO(type);
    567
    568static struct attribute *dock_attributes[] = {
    569	&dev_attr_docked.attr,
    570	&dev_attr_flags.attr,
    571	&dev_attr_undock.attr,
    572	&dev_attr_uid.attr,
    573	&dev_attr_type.attr,
    574	NULL
    575};
    576
    577static const struct attribute_group dock_attribute_group = {
    578	.attrs = dock_attributes
    579};
    580
    581/**
    582 * acpi_dock_add - Add a new dock station
    583 * @adev: Dock station ACPI device object.
    584 *
    585 * allocated and initialize a new dock station device.
    586 */
    587void acpi_dock_add(struct acpi_device *adev)
    588{
    589	struct dock_station *dock_station, ds = { NULL, };
    590	struct platform_device_info pdevinfo;
    591	acpi_handle handle = adev->handle;
    592	struct platform_device *dd;
    593	int ret;
    594
    595	memset(&pdevinfo, 0, sizeof(pdevinfo));
    596	pdevinfo.name = "dock";
    597	pdevinfo.id = dock_station_count;
    598	pdevinfo.fwnode = acpi_fwnode_handle(adev);
    599	pdevinfo.data = &ds;
    600	pdevinfo.size_data = sizeof(ds);
    601	dd = platform_device_register_full(&pdevinfo);
    602	if (IS_ERR(dd))
    603		return;
    604
    605	dock_station = dd->dev.platform_data;
    606
    607	dock_station->handle = handle;
    608	dock_station->dock_device = dd;
    609	dock_station->last_dock_time = jiffies - HZ;
    610
    611	INIT_LIST_HEAD(&dock_station->sibling);
    612	INIT_LIST_HEAD(&dock_station->dependent_devices);
    613
    614	/* we want the dock device to send uevents */
    615	dev_set_uevent_suppress(&dd->dev, 0);
    616
    617	if (acpi_dock_match(handle))
    618		dock_station->flags |= DOCK_IS_DOCK;
    619	if (acpi_ata_match(handle))
    620		dock_station->flags |= DOCK_IS_ATA;
    621	if (acpi_device_is_battery(adev))
    622		dock_station->flags |= DOCK_IS_BAT;
    623
    624	ret = sysfs_create_group(&dd->dev.kobj, &dock_attribute_group);
    625	if (ret)
    626		goto err_unregister;
    627
    628	/* add the dock station as a device dependent on itself */
    629	ret = add_dock_dependent_device(dock_station, adev);
    630	if (ret)
    631		goto err_rmgroup;
    632
    633	dock_station_count++;
    634	list_add(&dock_station->sibling, &dock_stations);
    635	adev->flags.is_dock_station = true;
    636	dev_info(&adev->dev, "ACPI dock station (docks/bays count: %d)\n",
    637		 dock_station_count);
    638	return;
    639
    640err_rmgroup:
    641	sysfs_remove_group(&dd->dev.kobj, &dock_attribute_group);
    642
    643err_unregister:
    644	platform_device_unregister(dd);
    645	acpi_handle_err(handle, "%s encountered error %d\n", __func__, ret);
    646}