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

phy_common.c (14189B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3
      4  Broadcom B43 wireless driver
      5  Common PHY routines
      6
      7  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
      8  Copyright (c) 2005-2007 Stefano Brivio <stefano.brivio@polimi.it>
      9  Copyright (c) 2005-2008 Michael Buesch <m@bues.ch>
     10  Copyright (c) 2005, 2006 Danny van Dyk <kugelfang@gentoo.org>
     11  Copyright (c) 2005, 2006 Andreas Jaggi <andreas.jaggi@waterwave.ch>
     12
     13
     14*/
     15
     16#include "phy_common.h"
     17#include "phy_g.h"
     18#include "phy_a.h"
     19#include "phy_n.h"
     20#include "phy_lp.h"
     21#include "phy_ht.h"
     22#include "phy_lcn.h"
     23#include "phy_ac.h"
     24#include "b43.h"
     25#include "main.h"
     26
     27
     28int b43_phy_allocate(struct b43_wldev *dev)
     29{
     30	struct b43_phy *phy = &(dev->phy);
     31	int err;
     32
     33	phy->ops = NULL;
     34
     35	switch (phy->type) {
     36	case B43_PHYTYPE_G:
     37#ifdef CONFIG_B43_PHY_G
     38		phy->ops = &b43_phyops_g;
     39#endif
     40		break;
     41	case B43_PHYTYPE_N:
     42#ifdef CONFIG_B43_PHY_N
     43		phy->ops = &b43_phyops_n;
     44#endif
     45		break;
     46	case B43_PHYTYPE_LP:
     47#ifdef CONFIG_B43_PHY_LP
     48		phy->ops = &b43_phyops_lp;
     49#endif
     50		break;
     51	case B43_PHYTYPE_HT:
     52#ifdef CONFIG_B43_PHY_HT
     53		phy->ops = &b43_phyops_ht;
     54#endif
     55		break;
     56	case B43_PHYTYPE_LCN:
     57#ifdef CONFIG_B43_PHY_LCN
     58		phy->ops = &b43_phyops_lcn;
     59#endif
     60		break;
     61	case B43_PHYTYPE_AC:
     62#ifdef CONFIG_B43_PHY_AC
     63		phy->ops = &b43_phyops_ac;
     64#endif
     65		break;
     66	}
     67	if (B43_WARN_ON(!phy->ops))
     68		return -ENODEV;
     69
     70	err = phy->ops->allocate(dev);
     71	if (err)
     72		phy->ops = NULL;
     73
     74	return err;
     75}
     76
     77void b43_phy_free(struct b43_wldev *dev)
     78{
     79	dev->phy.ops->free(dev);
     80	dev->phy.ops = NULL;
     81}
     82
     83int b43_phy_init(struct b43_wldev *dev)
     84{
     85	struct b43_phy *phy = &dev->phy;
     86	const struct b43_phy_operations *ops = phy->ops;
     87	int err;
     88
     89	/* During PHY init we need to use some channel. On the first init this
     90	 * function is called *before* b43_op_config, so our pointer is NULL.
     91	 */
     92	if (!phy->chandef) {
     93		phy->chandef = &dev->wl->hw->conf.chandef;
     94		phy->channel = phy->chandef->chan->hw_value;
     95	}
     96
     97	phy->ops->switch_analog(dev, true);
     98	b43_software_rfkill(dev, false);
     99
    100	err = ops->init(dev);
    101	if (err) {
    102		b43err(dev->wl, "PHY init failed\n");
    103		goto err_block_rf;
    104	}
    105	phy->do_full_init = false;
    106
    107	err = b43_switch_channel(dev, phy->channel);
    108	if (err) {
    109		b43err(dev->wl, "PHY init: Channel switch to default failed\n");
    110		goto err_phy_exit;
    111	}
    112
    113	return 0;
    114
    115err_phy_exit:
    116	phy->do_full_init = true;
    117	if (ops->exit)
    118		ops->exit(dev);
    119err_block_rf:
    120	b43_software_rfkill(dev, true);
    121
    122	return err;
    123}
    124
    125void b43_phy_exit(struct b43_wldev *dev)
    126{
    127	const struct b43_phy_operations *ops = dev->phy.ops;
    128
    129	b43_software_rfkill(dev, true);
    130	dev->phy.do_full_init = true;
    131	if (ops->exit)
    132		ops->exit(dev);
    133}
    134
    135bool b43_has_hardware_pctl(struct b43_wldev *dev)
    136{
    137	if (!dev->phy.hardware_power_control)
    138		return false;
    139	if (!dev->phy.ops->supports_hwpctl)
    140		return false;
    141	return dev->phy.ops->supports_hwpctl(dev);
    142}
    143
    144void b43_radio_lock(struct b43_wldev *dev)
    145{
    146	u32 macctl;
    147
    148#if B43_DEBUG
    149	B43_WARN_ON(dev->phy.radio_locked);
    150	dev->phy.radio_locked = true;
    151#endif
    152
    153	macctl = b43_read32(dev, B43_MMIO_MACCTL);
    154	macctl |= B43_MACCTL_RADIOLOCK;
    155	b43_write32(dev, B43_MMIO_MACCTL, macctl);
    156	/* Commit the write and wait for the firmware
    157	 * to finish any radio register access. */
    158	b43_read32(dev, B43_MMIO_MACCTL);
    159	udelay(10);
    160}
    161
    162void b43_radio_unlock(struct b43_wldev *dev)
    163{
    164	u32 macctl;
    165
    166#if B43_DEBUG
    167	B43_WARN_ON(!dev->phy.radio_locked);
    168	dev->phy.radio_locked = false;
    169#endif
    170
    171	/* Commit any write */
    172	b43_read16(dev, B43_MMIO_PHY_VER);
    173	/* unlock */
    174	macctl = b43_read32(dev, B43_MMIO_MACCTL);
    175	macctl &= ~B43_MACCTL_RADIOLOCK;
    176	b43_write32(dev, B43_MMIO_MACCTL, macctl);
    177}
    178
    179void b43_phy_lock(struct b43_wldev *dev)
    180{
    181#if B43_DEBUG
    182	B43_WARN_ON(dev->phy.phy_locked);
    183	dev->phy.phy_locked = true;
    184#endif
    185	B43_WARN_ON(dev->dev->core_rev < 3);
    186
    187	if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP))
    188		b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
    189}
    190
    191void b43_phy_unlock(struct b43_wldev *dev)
    192{
    193#if B43_DEBUG
    194	B43_WARN_ON(!dev->phy.phy_locked);
    195	dev->phy.phy_locked = false;
    196#endif
    197	B43_WARN_ON(dev->dev->core_rev < 3);
    198
    199	if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP))
    200		b43_power_saving_ctl_bits(dev, 0);
    201}
    202
    203static inline void assert_mac_suspended(struct b43_wldev *dev)
    204{
    205	if (!B43_DEBUG)
    206		return;
    207	if ((b43_status(dev) >= B43_STAT_INITIALIZED) &&
    208	    (dev->mac_suspended <= 0)) {
    209		b43dbg(dev->wl, "PHY/RADIO register access with "
    210		       "enabled MAC.\n");
    211		dump_stack();
    212	}
    213}
    214
    215u16 b43_radio_read(struct b43_wldev *dev, u16 reg)
    216{
    217	assert_mac_suspended(dev);
    218	dev->phy.writes_counter = 0;
    219	return dev->phy.ops->radio_read(dev, reg);
    220}
    221
    222void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value)
    223{
    224	assert_mac_suspended(dev);
    225	if (b43_bus_host_is_pci(dev->dev) &&
    226	    ++dev->phy.writes_counter > B43_MAX_WRITES_IN_ROW) {
    227		b43_read32(dev, B43_MMIO_MACCTL);
    228		dev->phy.writes_counter = 1;
    229	}
    230	dev->phy.ops->radio_write(dev, reg, value);
    231}
    232
    233void b43_radio_mask(struct b43_wldev *dev, u16 offset, u16 mask)
    234{
    235	b43_radio_write16(dev, offset,
    236			  b43_radio_read16(dev, offset) & mask);
    237}
    238
    239void b43_radio_set(struct b43_wldev *dev, u16 offset, u16 set)
    240{
    241	b43_radio_write16(dev, offset,
    242			  b43_radio_read16(dev, offset) | set);
    243}
    244
    245void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
    246{
    247	b43_radio_write16(dev, offset,
    248			  (b43_radio_read16(dev, offset) & mask) | set);
    249}
    250
    251bool b43_radio_wait_value(struct b43_wldev *dev, u16 offset, u16 mask,
    252			  u16 value, int delay, int timeout)
    253{
    254	u16 val;
    255	int i;
    256
    257	for (i = 0; i < timeout; i += delay) {
    258		val = b43_radio_read(dev, offset);
    259		if ((val & mask) == value)
    260			return true;
    261		udelay(delay);
    262	}
    263	return false;
    264}
    265
    266u16 b43_phy_read(struct b43_wldev *dev, u16 reg)
    267{
    268	assert_mac_suspended(dev);
    269	dev->phy.writes_counter = 0;
    270
    271	if (dev->phy.ops->phy_read)
    272		return dev->phy.ops->phy_read(dev, reg);
    273
    274	b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
    275	return b43_read16(dev, B43_MMIO_PHY_DATA);
    276}
    277
    278void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value)
    279{
    280	assert_mac_suspended(dev);
    281	if (b43_bus_host_is_pci(dev->dev) &&
    282	    ++dev->phy.writes_counter > B43_MAX_WRITES_IN_ROW) {
    283		b43_read16(dev, B43_MMIO_PHY_VER);
    284		dev->phy.writes_counter = 1;
    285	}
    286
    287	if (dev->phy.ops->phy_write)
    288		return dev->phy.ops->phy_write(dev, reg, value);
    289
    290	b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
    291	b43_write16(dev, B43_MMIO_PHY_DATA, value);
    292}
    293
    294void b43_phy_copy(struct b43_wldev *dev, u16 destreg, u16 srcreg)
    295{
    296	b43_phy_write(dev, destreg, b43_phy_read(dev, srcreg));
    297}
    298
    299void b43_phy_mask(struct b43_wldev *dev, u16 offset, u16 mask)
    300{
    301	if (dev->phy.ops->phy_maskset) {
    302		assert_mac_suspended(dev);
    303		dev->phy.ops->phy_maskset(dev, offset, mask, 0);
    304	} else {
    305		b43_phy_write(dev, offset,
    306			      b43_phy_read(dev, offset) & mask);
    307	}
    308}
    309
    310void b43_phy_set(struct b43_wldev *dev, u16 offset, u16 set)
    311{
    312	if (dev->phy.ops->phy_maskset) {
    313		assert_mac_suspended(dev);
    314		dev->phy.ops->phy_maskset(dev, offset, 0xFFFF, set);
    315	} else {
    316		b43_phy_write(dev, offset,
    317			      b43_phy_read(dev, offset) | set);
    318	}
    319}
    320
    321void b43_phy_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set)
    322{
    323	if (dev->phy.ops->phy_maskset) {
    324		assert_mac_suspended(dev);
    325		dev->phy.ops->phy_maskset(dev, offset, mask, set);
    326	} else {
    327		b43_phy_write(dev, offset,
    328			      (b43_phy_read(dev, offset) & mask) | set);
    329	}
    330}
    331
    332void b43_phy_put_into_reset(struct b43_wldev *dev)
    333{
    334	u32 tmp;
    335
    336	switch (dev->dev->bus_type) {
    337#ifdef CONFIG_B43_BCMA
    338	case B43_BUS_BCMA:
    339		tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
    340		tmp &= ~B43_BCMA_IOCTL_GMODE;
    341		tmp |= B43_BCMA_IOCTL_PHY_RESET;
    342		tmp |= BCMA_IOCTL_FGC;
    343		bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
    344		udelay(1);
    345
    346		tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
    347		tmp &= ~BCMA_IOCTL_FGC;
    348		bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
    349		udelay(1);
    350		break;
    351#endif
    352#ifdef CONFIG_B43_SSB
    353	case B43_BUS_SSB:
    354		tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
    355		tmp &= ~B43_TMSLOW_GMODE;
    356		tmp |= B43_TMSLOW_PHYRESET;
    357		tmp |= SSB_TMSLOW_FGC;
    358		ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
    359		usleep_range(1000, 2000);
    360
    361		tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
    362		tmp &= ~SSB_TMSLOW_FGC;
    363		ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
    364		usleep_range(1000, 2000);
    365
    366		break;
    367#endif
    368	}
    369}
    370
    371void b43_phy_take_out_of_reset(struct b43_wldev *dev)
    372{
    373	u32 tmp;
    374
    375	switch (dev->dev->bus_type) {
    376#ifdef CONFIG_B43_BCMA
    377	case B43_BUS_BCMA:
    378		/* Unset reset bit (with forcing clock) */
    379		tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
    380		tmp &= ~B43_BCMA_IOCTL_PHY_RESET;
    381		tmp &= ~B43_BCMA_IOCTL_PHY_CLKEN;
    382		tmp |= BCMA_IOCTL_FGC;
    383		bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
    384		udelay(1);
    385
    386		/* Do not force clock anymore */
    387		tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
    388		tmp &= ~BCMA_IOCTL_FGC;
    389		tmp |= B43_BCMA_IOCTL_PHY_CLKEN;
    390		bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
    391		udelay(1);
    392		break;
    393#endif
    394#ifdef CONFIG_B43_SSB
    395	case B43_BUS_SSB:
    396		/* Unset reset bit (with forcing clock) */
    397		tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
    398		tmp &= ~B43_TMSLOW_PHYRESET;
    399		tmp &= ~B43_TMSLOW_PHYCLKEN;
    400		tmp |= SSB_TMSLOW_FGC;
    401		ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
    402		ssb_read32(dev->dev->sdev, SSB_TMSLOW); /* flush */
    403		usleep_range(1000, 2000);
    404
    405		tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
    406		tmp &= ~SSB_TMSLOW_FGC;
    407		tmp |= B43_TMSLOW_PHYCLKEN;
    408		ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
    409		ssb_read32(dev->dev->sdev, SSB_TMSLOW); /* flush */
    410		usleep_range(1000, 2000);
    411		break;
    412#endif
    413	}
    414}
    415
    416int b43_switch_channel(struct b43_wldev *dev, unsigned int new_channel)
    417{
    418	struct b43_phy *phy = &(dev->phy);
    419	u16 channelcookie, savedcookie;
    420	int err;
    421
    422	/* First we set the channel radio code to prevent the
    423	 * firmware from sending ghost packets.
    424	 */
    425	channelcookie = new_channel;
    426	if (b43_current_band(dev->wl) == NL80211_BAND_5GHZ)
    427		channelcookie |= B43_SHM_SH_CHAN_5GHZ;
    428	/* FIXME: set 40Mhz flag if required */
    429	if (0)
    430		channelcookie |= B43_SHM_SH_CHAN_40MHZ;
    431	savedcookie = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN);
    432	b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_CHAN, channelcookie);
    433
    434	/* Now try to switch the PHY hardware channel. */
    435	err = phy->ops->switch_channel(dev, new_channel);
    436	if (err)
    437		goto err_restore_cookie;
    438
    439	/* Wait for the radio to tune to the channel and stabilize. */
    440	msleep(8);
    441
    442	return 0;
    443
    444err_restore_cookie:
    445	b43_shm_write16(dev, B43_SHM_SHARED,
    446			B43_SHM_SH_CHAN, savedcookie);
    447
    448	return err;
    449}
    450
    451void b43_software_rfkill(struct b43_wldev *dev, bool blocked)
    452{
    453	struct b43_phy *phy = &dev->phy;
    454
    455	b43_mac_suspend(dev);
    456	phy->ops->software_rfkill(dev, blocked);
    457	phy->radio_on = !blocked;
    458	b43_mac_enable(dev);
    459}
    460
    461/*
    462 * b43_phy_txpower_adjust_work - TX power workqueue.
    463 *
    464 * Workqueue for updating the TX power parameters in hardware.
    465 */
    466void b43_phy_txpower_adjust_work(struct work_struct *work)
    467{
    468	struct b43_wl *wl = container_of(work, struct b43_wl,
    469					 txpower_adjust_work);
    470	struct b43_wldev *dev;
    471
    472	mutex_lock(&wl->mutex);
    473	dev = wl->current_dev;
    474
    475	if (likely(dev && (b43_status(dev) >= B43_STAT_STARTED)))
    476		dev->phy.ops->adjust_txpower(dev);
    477
    478	mutex_unlock(&wl->mutex);
    479}
    480
    481void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags)
    482{
    483	struct b43_phy *phy = &dev->phy;
    484	unsigned long now = jiffies;
    485	enum b43_txpwr_result result;
    486
    487	if (!(flags & B43_TXPWR_IGNORE_TIME)) {
    488		/* Check if it's time for a TXpower check. */
    489		if (time_before(now, phy->next_txpwr_check_time))
    490			return; /* Not yet */
    491	}
    492	/* The next check will be needed in two seconds, or later. */
    493	phy->next_txpwr_check_time = round_jiffies(now + (HZ * 2));
    494
    495	if ((dev->dev->board_vendor == SSB_BOARDVENDOR_BCM) &&
    496	    (dev->dev->board_type == SSB_BOARD_BU4306))
    497		return; /* No software txpower adjustment needed */
    498
    499	result = phy->ops->recalc_txpower(dev, !!(flags & B43_TXPWR_IGNORE_TSSI));
    500	if (result == B43_TXPWR_RES_DONE)
    501		return; /* We are done. */
    502	B43_WARN_ON(result != B43_TXPWR_RES_NEED_ADJUST);
    503	B43_WARN_ON(phy->ops->adjust_txpower == NULL);
    504
    505	/* We must adjust the transmission power in hardware.
    506	 * Schedule b43_phy_txpower_adjust_work(). */
    507	ieee80211_queue_work(dev->wl->hw, &dev->wl->txpower_adjust_work);
    508}
    509
    510int b43_phy_shm_tssi_read(struct b43_wldev *dev, u16 shm_offset)
    511{
    512	const bool is_ofdm = (shm_offset != B43_SHM_SH_TSSI_CCK);
    513	unsigned int a, b, c, d;
    514	unsigned int average;
    515	u32 tmp;
    516
    517	tmp = b43_shm_read32(dev, B43_SHM_SHARED, shm_offset);
    518	a = tmp & 0xFF;
    519	b = (tmp >> 8) & 0xFF;
    520	c = (tmp >> 16) & 0xFF;
    521	d = (tmp >> 24) & 0xFF;
    522	if (a == 0 || a == B43_TSSI_MAX ||
    523	    b == 0 || b == B43_TSSI_MAX ||
    524	    c == 0 || c == B43_TSSI_MAX ||
    525	    d == 0 || d == B43_TSSI_MAX)
    526		return -ENOENT;
    527	/* The values are OK. Clear them. */
    528	tmp = B43_TSSI_MAX | (B43_TSSI_MAX << 8) |
    529	      (B43_TSSI_MAX << 16) | (B43_TSSI_MAX << 24);
    530	b43_shm_write32(dev, B43_SHM_SHARED, shm_offset, tmp);
    531
    532	if (is_ofdm) {
    533		a = (a + 32) & 0x3F;
    534		b = (b + 32) & 0x3F;
    535		c = (c + 32) & 0x3F;
    536		d = (d + 32) & 0x3F;
    537	}
    538
    539	/* Get the average of the values with 0.5 added to each value. */
    540	average = (a + b + c + d + 2) / 4;
    541	if (is_ofdm) {
    542		/* Adjust for CCK-boost */
    543		if (b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_HOSTF1)
    544		    & B43_HF_CCKBOOST)
    545			average = (average >= 13) ? (average - 13) : 0;
    546	}
    547
    548	return average;
    549}
    550
    551void b43_phyop_switch_analog_generic(struct b43_wldev *dev, bool on)
    552{
    553	b43_write16(dev, B43_MMIO_PHY0, on ? 0 : 0xF4);
    554}
    555
    556
    557bool b43_is_40mhz(struct b43_wldev *dev)
    558{
    559	return dev->phy.chandef->width == NL80211_CHAN_WIDTH_40;
    560}
    561
    562/* https://bcm-v4.sipsolutions.net/802.11/PHY/N/BmacPhyClkFgc */
    563void b43_phy_force_clock(struct b43_wldev *dev, bool force)
    564{
    565	u32 tmp;
    566
    567	WARN_ON(dev->phy.type != B43_PHYTYPE_N &&
    568		dev->phy.type != B43_PHYTYPE_HT &&
    569		dev->phy.type != B43_PHYTYPE_AC);
    570
    571	switch (dev->dev->bus_type) {
    572#ifdef CONFIG_B43_BCMA
    573	case B43_BUS_BCMA:
    574		tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
    575		if (force)
    576			tmp |= BCMA_IOCTL_FGC;
    577		else
    578			tmp &= ~BCMA_IOCTL_FGC;
    579		bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
    580		break;
    581#endif
    582#ifdef CONFIG_B43_SSB
    583	case B43_BUS_SSB:
    584		tmp = ssb_read32(dev->dev->sdev, SSB_TMSLOW);
    585		if (force)
    586			tmp |= SSB_TMSLOW_FGC;
    587		else
    588			tmp &= ~SSB_TMSLOW_FGC;
    589		ssb_write32(dev->dev->sdev, SSB_TMSLOW, tmp);
    590		break;
    591#endif
    592	}
    593}