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

led.c (9837B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright 2006, Johannes Berg <johannes@sipsolutions.net>
      4 */
      5
      6/* just for IFNAMSIZ */
      7#include <linux/if.h>
      8#include <linux/slab.h>
      9#include <linux/export.h>
     10#include "led.h"
     11
     12void ieee80211_led_assoc(struct ieee80211_local *local, bool associated)
     13{
     14	if (!atomic_read(&local->assoc_led_active))
     15		return;
     16	if (associated)
     17		led_trigger_event(&local->assoc_led, LED_FULL);
     18	else
     19		led_trigger_event(&local->assoc_led, LED_OFF);
     20}
     21
     22void ieee80211_led_radio(struct ieee80211_local *local, bool enabled)
     23{
     24	if (!atomic_read(&local->radio_led_active))
     25		return;
     26	if (enabled)
     27		led_trigger_event(&local->radio_led, LED_FULL);
     28	else
     29		led_trigger_event(&local->radio_led, LED_OFF);
     30}
     31
     32void ieee80211_alloc_led_names(struct ieee80211_local *local)
     33{
     34	local->rx_led.name = kasprintf(GFP_KERNEL, "%srx",
     35				       wiphy_name(local->hw.wiphy));
     36	local->tx_led.name = kasprintf(GFP_KERNEL, "%stx",
     37				       wiphy_name(local->hw.wiphy));
     38	local->assoc_led.name = kasprintf(GFP_KERNEL, "%sassoc",
     39					  wiphy_name(local->hw.wiphy));
     40	local->radio_led.name = kasprintf(GFP_KERNEL, "%sradio",
     41					  wiphy_name(local->hw.wiphy));
     42}
     43
     44void ieee80211_free_led_names(struct ieee80211_local *local)
     45{
     46	kfree(local->rx_led.name);
     47	kfree(local->tx_led.name);
     48	kfree(local->assoc_led.name);
     49	kfree(local->radio_led.name);
     50}
     51
     52static int ieee80211_tx_led_activate(struct led_classdev *led_cdev)
     53{
     54	struct ieee80211_local *local = container_of(led_cdev->trigger,
     55						     struct ieee80211_local,
     56						     tx_led);
     57
     58	atomic_inc(&local->tx_led_active);
     59
     60	return 0;
     61}
     62
     63static void ieee80211_tx_led_deactivate(struct led_classdev *led_cdev)
     64{
     65	struct ieee80211_local *local = container_of(led_cdev->trigger,
     66						     struct ieee80211_local,
     67						     tx_led);
     68
     69	atomic_dec(&local->tx_led_active);
     70}
     71
     72static int ieee80211_rx_led_activate(struct led_classdev *led_cdev)
     73{
     74	struct ieee80211_local *local = container_of(led_cdev->trigger,
     75						     struct ieee80211_local,
     76						     rx_led);
     77
     78	atomic_inc(&local->rx_led_active);
     79
     80	return 0;
     81}
     82
     83static void ieee80211_rx_led_deactivate(struct led_classdev *led_cdev)
     84{
     85	struct ieee80211_local *local = container_of(led_cdev->trigger,
     86						     struct ieee80211_local,
     87						     rx_led);
     88
     89	atomic_dec(&local->rx_led_active);
     90}
     91
     92static int ieee80211_assoc_led_activate(struct led_classdev *led_cdev)
     93{
     94	struct ieee80211_local *local = container_of(led_cdev->trigger,
     95						     struct ieee80211_local,
     96						     assoc_led);
     97
     98	atomic_inc(&local->assoc_led_active);
     99
    100	return 0;
    101}
    102
    103static void ieee80211_assoc_led_deactivate(struct led_classdev *led_cdev)
    104{
    105	struct ieee80211_local *local = container_of(led_cdev->trigger,
    106						     struct ieee80211_local,
    107						     assoc_led);
    108
    109	atomic_dec(&local->assoc_led_active);
    110}
    111
    112static int ieee80211_radio_led_activate(struct led_classdev *led_cdev)
    113{
    114	struct ieee80211_local *local = container_of(led_cdev->trigger,
    115						     struct ieee80211_local,
    116						     radio_led);
    117
    118	atomic_inc(&local->radio_led_active);
    119
    120	return 0;
    121}
    122
    123static void ieee80211_radio_led_deactivate(struct led_classdev *led_cdev)
    124{
    125	struct ieee80211_local *local = container_of(led_cdev->trigger,
    126						     struct ieee80211_local,
    127						     radio_led);
    128
    129	atomic_dec(&local->radio_led_active);
    130}
    131
    132static int ieee80211_tpt_led_activate(struct led_classdev *led_cdev)
    133{
    134	struct ieee80211_local *local = container_of(led_cdev->trigger,
    135						     struct ieee80211_local,
    136						     tpt_led);
    137
    138	atomic_inc(&local->tpt_led_active);
    139
    140	return 0;
    141}
    142
    143static void ieee80211_tpt_led_deactivate(struct led_classdev *led_cdev)
    144{
    145	struct ieee80211_local *local = container_of(led_cdev->trigger,
    146						     struct ieee80211_local,
    147						     tpt_led);
    148
    149	atomic_dec(&local->tpt_led_active);
    150}
    151
    152void ieee80211_led_init(struct ieee80211_local *local)
    153{
    154	atomic_set(&local->rx_led_active, 0);
    155	local->rx_led.activate = ieee80211_rx_led_activate;
    156	local->rx_led.deactivate = ieee80211_rx_led_deactivate;
    157	if (local->rx_led.name && led_trigger_register(&local->rx_led)) {
    158		kfree(local->rx_led.name);
    159		local->rx_led.name = NULL;
    160	}
    161
    162	atomic_set(&local->tx_led_active, 0);
    163	local->tx_led.activate = ieee80211_tx_led_activate;
    164	local->tx_led.deactivate = ieee80211_tx_led_deactivate;
    165	if (local->tx_led.name && led_trigger_register(&local->tx_led)) {
    166		kfree(local->tx_led.name);
    167		local->tx_led.name = NULL;
    168	}
    169
    170	atomic_set(&local->assoc_led_active, 0);
    171	local->assoc_led.activate = ieee80211_assoc_led_activate;
    172	local->assoc_led.deactivate = ieee80211_assoc_led_deactivate;
    173	if (local->assoc_led.name && led_trigger_register(&local->assoc_led)) {
    174		kfree(local->assoc_led.name);
    175		local->assoc_led.name = NULL;
    176	}
    177
    178	atomic_set(&local->radio_led_active, 0);
    179	local->radio_led.activate = ieee80211_radio_led_activate;
    180	local->radio_led.deactivate = ieee80211_radio_led_deactivate;
    181	if (local->radio_led.name && led_trigger_register(&local->radio_led)) {
    182		kfree(local->radio_led.name);
    183		local->radio_led.name = NULL;
    184	}
    185
    186	atomic_set(&local->tpt_led_active, 0);
    187	if (local->tpt_led_trigger) {
    188		local->tpt_led.activate = ieee80211_tpt_led_activate;
    189		local->tpt_led.deactivate = ieee80211_tpt_led_deactivate;
    190		if (led_trigger_register(&local->tpt_led)) {
    191			kfree(local->tpt_led_trigger);
    192			local->tpt_led_trigger = NULL;
    193		}
    194	}
    195}
    196
    197void ieee80211_led_exit(struct ieee80211_local *local)
    198{
    199	if (local->radio_led.name)
    200		led_trigger_unregister(&local->radio_led);
    201	if (local->assoc_led.name)
    202		led_trigger_unregister(&local->assoc_led);
    203	if (local->tx_led.name)
    204		led_trigger_unregister(&local->tx_led);
    205	if (local->rx_led.name)
    206		led_trigger_unregister(&local->rx_led);
    207
    208	if (local->tpt_led_trigger) {
    209		led_trigger_unregister(&local->tpt_led);
    210		kfree(local->tpt_led_trigger);
    211	}
    212}
    213
    214const char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
    215{
    216	struct ieee80211_local *local = hw_to_local(hw);
    217
    218	return local->radio_led.name;
    219}
    220EXPORT_SYMBOL(__ieee80211_get_radio_led_name);
    221
    222const char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
    223{
    224	struct ieee80211_local *local = hw_to_local(hw);
    225
    226	return local->assoc_led.name;
    227}
    228EXPORT_SYMBOL(__ieee80211_get_assoc_led_name);
    229
    230const char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
    231{
    232	struct ieee80211_local *local = hw_to_local(hw);
    233
    234	return local->tx_led.name;
    235}
    236EXPORT_SYMBOL(__ieee80211_get_tx_led_name);
    237
    238const char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
    239{
    240	struct ieee80211_local *local = hw_to_local(hw);
    241
    242	return local->rx_led.name;
    243}
    244EXPORT_SYMBOL(__ieee80211_get_rx_led_name);
    245
    246static unsigned long tpt_trig_traffic(struct ieee80211_local *local,
    247				      struct tpt_led_trigger *tpt_trig)
    248{
    249	unsigned long traffic, delta;
    250
    251	traffic = tpt_trig->tx_bytes + tpt_trig->rx_bytes;
    252
    253	delta = traffic - tpt_trig->prev_traffic;
    254	tpt_trig->prev_traffic = traffic;
    255	return DIV_ROUND_UP(delta, 1024 / 8);
    256}
    257
    258static void tpt_trig_timer(struct timer_list *t)
    259{
    260	struct tpt_led_trigger *tpt_trig = from_timer(tpt_trig, t, timer);
    261	struct ieee80211_local *local = tpt_trig->local;
    262	unsigned long on, off, tpt;
    263	int i;
    264
    265	if (!tpt_trig->running)
    266		return;
    267
    268	mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ));
    269
    270	tpt = tpt_trig_traffic(local, tpt_trig);
    271
    272	/* default to just solid on */
    273	on = 1;
    274	off = 0;
    275
    276	for (i = tpt_trig->blink_table_len - 1; i >= 0; i--) {
    277		if (tpt_trig->blink_table[i].throughput < 0 ||
    278		    tpt > tpt_trig->blink_table[i].throughput) {
    279			off = tpt_trig->blink_table[i].blink_time / 2;
    280			on = tpt_trig->blink_table[i].blink_time - off;
    281			break;
    282		}
    283	}
    284
    285	led_trigger_blink(&local->tpt_led, &on, &off);
    286}
    287
    288const char *
    289__ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
    290				   unsigned int flags,
    291				   const struct ieee80211_tpt_blink *blink_table,
    292				   unsigned int blink_table_len)
    293{
    294	struct ieee80211_local *local = hw_to_local(hw);
    295	struct tpt_led_trigger *tpt_trig;
    296
    297	if (WARN_ON(local->tpt_led_trigger))
    298		return NULL;
    299
    300	tpt_trig = kzalloc(sizeof(struct tpt_led_trigger), GFP_KERNEL);
    301	if (!tpt_trig)
    302		return NULL;
    303
    304	snprintf(tpt_trig->name, sizeof(tpt_trig->name),
    305		 "%stpt", wiphy_name(local->hw.wiphy));
    306
    307	local->tpt_led.name = tpt_trig->name;
    308
    309	tpt_trig->blink_table = blink_table;
    310	tpt_trig->blink_table_len = blink_table_len;
    311	tpt_trig->want = flags;
    312	tpt_trig->local = local;
    313
    314	timer_setup(&tpt_trig->timer, tpt_trig_timer, 0);
    315
    316	local->tpt_led_trigger = tpt_trig;
    317
    318	return tpt_trig->name;
    319}
    320EXPORT_SYMBOL(__ieee80211_create_tpt_led_trigger);
    321
    322static void ieee80211_start_tpt_led_trig(struct ieee80211_local *local)
    323{
    324	struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
    325
    326	if (tpt_trig->running)
    327		return;
    328
    329	/* reset traffic */
    330	tpt_trig_traffic(local, tpt_trig);
    331	tpt_trig->running = true;
    332
    333	tpt_trig_timer(&tpt_trig->timer);
    334	mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ));
    335}
    336
    337static void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local)
    338{
    339	struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
    340
    341	if (!tpt_trig->running)
    342		return;
    343
    344	tpt_trig->running = false;
    345	del_timer_sync(&tpt_trig->timer);
    346
    347	led_trigger_event(&local->tpt_led, LED_OFF);
    348}
    349
    350void ieee80211_mod_tpt_led_trig(struct ieee80211_local *local,
    351				unsigned int types_on, unsigned int types_off)
    352{
    353	struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
    354	bool allowed;
    355
    356	WARN_ON(types_on & types_off);
    357
    358	if (!tpt_trig)
    359		return;
    360
    361	tpt_trig->active &= ~types_off;
    362	tpt_trig->active |= types_on;
    363
    364	/*
    365	 * Regardless of wanted state, we shouldn't blink when
    366	 * the radio is disabled -- this can happen due to some
    367	 * code ordering issues with __ieee80211_recalc_idle()
    368	 * being called before the radio is started.
    369	 */
    370	allowed = tpt_trig->active & IEEE80211_TPT_LEDTRIG_FL_RADIO;
    371
    372	if (!allowed || !(tpt_trig->active & tpt_trig->want))
    373		ieee80211_stop_tpt_led_trig(local);
    374	else
    375		ieee80211_start_tpt_led_trig(local);
    376}