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

swphy.c (3792B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Software PHY emulation
      4 *
      5 * Code taken from fixed_phy.c by Russell King.
      6 *
      7 * Author: Vitaly Bordug <vbordug@ru.mvista.com>
      8 *         Anton Vorontsov <avorontsov@ru.mvista.com>
      9 *
     10 * Copyright (c) 2006-2007 MontaVista Software, Inc.
     11 */
     12#include <linux/export.h>
     13#include <linux/mii.h>
     14#include <linux/phy.h>
     15#include <linux/phy_fixed.h>
     16
     17#include "swphy.h"
     18
     19#define MII_REGS_NUM 29
     20
     21struct swmii_regs {
     22	u16 bmsr;
     23	u16 lpa;
     24	u16 lpagb;
     25	u16 estat;
     26};
     27
     28enum {
     29	SWMII_SPEED_10 = 0,
     30	SWMII_SPEED_100,
     31	SWMII_SPEED_1000,
     32	SWMII_DUPLEX_HALF = 0,
     33	SWMII_DUPLEX_FULL,
     34};
     35
     36/*
     37 * These two tables get bitwise-anded together to produce the final result.
     38 * This means the speed table must contain both duplex settings, and the
     39 * duplex table must contain all speed settings.
     40 */
     41static const struct swmii_regs speed[] = {
     42	[SWMII_SPEED_10] = {
     43		.lpa   = LPA_10FULL | LPA_10HALF,
     44	},
     45	[SWMII_SPEED_100] = {
     46		.bmsr  = BMSR_100FULL | BMSR_100HALF,
     47		.lpa   = LPA_100FULL | LPA_100HALF,
     48	},
     49	[SWMII_SPEED_1000] = {
     50		.bmsr  = BMSR_ESTATEN,
     51		.lpagb = LPA_1000FULL | LPA_1000HALF,
     52		.estat = ESTATUS_1000_TFULL | ESTATUS_1000_THALF,
     53	},
     54};
     55
     56static const struct swmii_regs duplex[] = {
     57	[SWMII_DUPLEX_HALF] = {
     58		.bmsr  = BMSR_ESTATEN | BMSR_100HALF,
     59		.lpa   = LPA_10HALF | LPA_100HALF,
     60		.lpagb = LPA_1000HALF,
     61		.estat = ESTATUS_1000_THALF,
     62	},
     63	[SWMII_DUPLEX_FULL] = {
     64		.bmsr  = BMSR_ESTATEN | BMSR_100FULL,
     65		.lpa   = LPA_10FULL | LPA_100FULL,
     66		.lpagb = LPA_1000FULL,
     67		.estat = ESTATUS_1000_TFULL,
     68	},
     69};
     70
     71static int swphy_decode_speed(int speed)
     72{
     73	switch (speed) {
     74	case 1000:
     75		return SWMII_SPEED_1000;
     76	case 100:
     77		return SWMII_SPEED_100;
     78	case 10:
     79		return SWMII_SPEED_10;
     80	default:
     81		return -EINVAL;
     82	}
     83}
     84
     85/**
     86 * swphy_validate_state - validate the software phy status
     87 * @state: software phy status
     88 *
     89 * This checks that we can represent the state stored in @state can be
     90 * represented in the emulated MII registers.  Returns 0 if it can,
     91 * otherwise returns -EINVAL.
     92 */
     93int swphy_validate_state(const struct fixed_phy_status *state)
     94{
     95	int err;
     96
     97	if (state->link) {
     98		err = swphy_decode_speed(state->speed);
     99		if (err < 0) {
    100			pr_warn("swphy: unknown speed\n");
    101			return -EINVAL;
    102		}
    103	}
    104	return 0;
    105}
    106EXPORT_SYMBOL_GPL(swphy_validate_state);
    107
    108/**
    109 * swphy_read_reg - return a MII register from the fixed phy state
    110 * @reg: MII register
    111 * @state: fixed phy status
    112 *
    113 * Return the MII @reg register generated from the fixed phy state @state.
    114 */
    115int swphy_read_reg(int reg, const struct fixed_phy_status *state)
    116{
    117	int speed_index, duplex_index;
    118	u16 bmsr = BMSR_ANEGCAPABLE;
    119	u16 estat = 0;
    120	u16 lpagb = 0;
    121	u16 lpa = 0;
    122
    123	if (reg > MII_REGS_NUM)
    124		return -1;
    125
    126	speed_index = swphy_decode_speed(state->speed);
    127	if (WARN_ON(speed_index < 0))
    128		return 0;
    129
    130	duplex_index = state->duplex ? SWMII_DUPLEX_FULL : SWMII_DUPLEX_HALF;
    131
    132	bmsr |= speed[speed_index].bmsr & duplex[duplex_index].bmsr;
    133	estat |= speed[speed_index].estat & duplex[duplex_index].estat;
    134
    135	if (state->link) {
    136		bmsr |= BMSR_LSTATUS | BMSR_ANEGCOMPLETE;
    137
    138		lpa   |= speed[speed_index].lpa   & duplex[duplex_index].lpa;
    139		lpagb |= speed[speed_index].lpagb & duplex[duplex_index].lpagb;
    140
    141		if (state->pause)
    142			lpa |= LPA_PAUSE_CAP;
    143
    144		if (state->asym_pause)
    145			lpa |= LPA_PAUSE_ASYM;
    146	}
    147
    148	switch (reg) {
    149	case MII_BMCR:
    150		return BMCR_ANENABLE;
    151	case MII_BMSR:
    152		return bmsr;
    153	case MII_PHYSID1:
    154	case MII_PHYSID2:
    155		return 0;
    156	case MII_LPA:
    157		return lpa;
    158	case MII_STAT1000:
    159		return lpagb;
    160	case MII_ESTATUS:
    161		return estat;
    162
    163	/*
    164	 * We do not support emulating Clause 45 over Clause 22 register
    165	 * reads.  Return an error instead of bogus data.
    166	 */
    167	case MII_MMD_CTRL:
    168	case MII_MMD_DATA:
    169		return -1;
    170
    171	default:
    172		return 0xffff;
    173	}
    174}
    175EXPORT_SYMBOL_GPL(swphy_read_reg);