123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- From: Russell King <[email protected]>
- Date: Thu, 5 Jan 2017 16:47:39 +0000
- Subject: [PATCH] net: phy: move phy_lookup_setting() and guts of
- phy_supported_speeds() to phy-core
- phy_lookup_setting() provides useful functionality in ethtool code
- outside phylib. Move it to phy-core and allow it to be re-used (eg,
- in phylink) rather than duplicated elsewhere. Note that this supports
- the larger linkmode space.
- As we move the phy settings table, we also need to move the guts of
- phy_supported_speeds() as well.
- Signed-off-by: Russell King <[email protected]>
- ---
- --- a/drivers/net/phy/phy.c
- +++ b/drivers/net/phy/phy.c
- @@ -149,125 +149,6 @@ static inline int phy_aneg_done(struct p
- return genphy_aneg_done(phydev);
- }
-
- -/* A structure for mapping a particular speed and duplex
- - * combination to a particular SUPPORTED and ADVERTISED value
- - */
- -struct phy_setting {
- - int speed;
- - int duplex;
- - int bit;
- -};
- -
- -/* A mapping of all SUPPORTED settings to speed/duplex. This table
- - * must be grouped by speed and sorted in descending match priority
- - * - iow, descending speed. */
- -static const struct phy_setting settings[] = {
- - {
- - .speed = SPEED_10000,
- - .duplex = DUPLEX_FULL,
- - .bit = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
- - },
- - {
- - .speed = SPEED_10000,
- - .duplex = DUPLEX_FULL,
- - .bit = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
- - },
- - {
- - .speed = SPEED_10000,
- - .duplex = DUPLEX_FULL,
- - .bit = ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
- - },
- - {
- - .speed = SPEED_2500,
- - .duplex = DUPLEX_FULL,
- - .bit = ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
- - },
- - {
- - .speed = SPEED_1000,
- - .duplex = DUPLEX_FULL,
- - .bit = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
- - },
- - {
- - .speed = SPEED_1000,
- - .duplex = DUPLEX_FULL,
- - .bit = ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
- - },
- - {
- - .speed = SPEED_1000,
- - .duplex = DUPLEX_HALF,
- - .bit = ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
- - },
- - {
- - .speed = SPEED_100,
- - .duplex = DUPLEX_FULL,
- - .bit = ETHTOOL_LINK_MODE_100baseT_Full_BIT,
- - },
- - {
- - .speed = SPEED_100,
- - .duplex = DUPLEX_HALF,
- - .bit = ETHTOOL_LINK_MODE_100baseT_Half_BIT,
- - },
- - {
- - .speed = SPEED_10,
- - .duplex = DUPLEX_FULL,
- - .bit = ETHTOOL_LINK_MODE_10baseT_Full_BIT,
- - },
- - {
- - .speed = SPEED_10,
- - .duplex = DUPLEX_HALF,
- - .bit = ETHTOOL_LINK_MODE_10baseT_Half_BIT,
- - },
- -};
- -
- -/**
- - * phy_lookup_setting - lookup a PHY setting
- - * @speed: speed to match
- - * @duplex: duplex to match
- - * @mask: allowed link modes
- - * @maxbit: bit size of link modes
- - * @exact: an exact match is required
- - *
- - * Search the settings array for a setting that matches the speed and
- - * duplex, and which is supported.
- - *
- - * If @exact is unset, either an exact match or %NULL for no match will
- - * be returned.
- - *
- - * If @exact is set, an exact match, the fastest supported setting at
- - * or below the specified speed, the slowest supported setting, or if
- - * they all fail, %NULL will be returned.
- - */
- -static const struct phy_setting *
- -phy_lookup_setting(int speed, int duplex, const unsigned long *mask,
- - size_t maxbit, bool exact)
- -{
- - const struct phy_setting *p, *match = NULL, *last = NULL;
- - int i;
- -
- - for (i = 0, p = settings; i < ARRAY_SIZE(settings); i++, p++) {
- - if (p->bit < maxbit && test_bit(p->bit, mask)) {
- - last = p;
- - if (p->speed == speed && p->duplex == duplex) {
- - /* Exact match for speed and duplex */
- - match = p;
- - break;
- - } else if (!exact) {
- - if (!match && p->speed <= speed)
- - /* Candidate */
- - match = p;
- -
- - if (p->speed < speed)
- - break;
- - }
- - }
- - }
- -
- - if (!match && !exact)
- - match = last;
- -
- - return match;
- -}
- -
- /**
- * phy_find_valid - find a PHY setting that matches the requested parameters
- * @speed: desired speed
- @@ -290,6 +171,25 @@ phy_find_valid(int speed, int duplex, u3
- }
-
- /**
- + * phy_supported_speeds - return all speeds currently supported by a phy device
- + * @phy: The phy device to return supported speeds of.
- + * @speeds: buffer to store supported speeds in.
- + * @size: size of speeds buffer.
- + *
- + * Description: Returns the number of supported speeds, and fills the speeds
- + * buffer with the supported speeds. If speeds buffer is too small to contain
- + * all currently supported speeds, will return as many speeds as can fit.
- + */
- +unsigned int phy_supported_speeds(struct phy_device *phy,
- + unsigned int *speeds,
- + unsigned int size)
- +{
- + unsigned long supported = phy->supported;
- +
- + return phy_speeds(speeds, size, &supported, BITS_PER_LONG);
- +}
- +
- +/**
- * phy_check_valid - check if there is a valid PHY setting which matches
- * speed, duplex, and feature mask
- * @speed: speed to match
- --- a/drivers/net/phy/phy-core.c
- +++ b/drivers/net/phy/phy-core.c
- @@ -42,6 +42,132 @@ const char *phy_duplex_to_str(unsigned i
- }
- EXPORT_SYMBOL_GPL(phy_duplex_to_str);
-
- +/* A mapping of all SUPPORTED settings to speed/duplex. This table
- + * must be grouped by speed and sorted in descending match priority
- + * - iow, descending speed. */
- +static const struct phy_setting settings[] = {
- + {
- + .speed = SPEED_10000,
- + .duplex = DUPLEX_FULL,
- + .bit = ETHTOOL_LINK_MODE_10000baseKR_Full_BIT,
- + },
- + {
- + .speed = SPEED_10000,
- + .duplex = DUPLEX_FULL,
- + .bit = ETHTOOL_LINK_MODE_10000baseKX4_Full_BIT,
- + },
- + {
- + .speed = SPEED_10000,
- + .duplex = DUPLEX_FULL,
- + .bit = ETHTOOL_LINK_MODE_10000baseT_Full_BIT,
- + },
- + {
- + .speed = SPEED_2500,
- + .duplex = DUPLEX_FULL,
- + .bit = ETHTOOL_LINK_MODE_2500baseX_Full_BIT,
- + },
- + {
- + .speed = SPEED_1000,
- + .duplex = DUPLEX_FULL,
- + .bit = ETHTOOL_LINK_MODE_1000baseKX_Full_BIT,
- + },
- + {
- + .speed = SPEED_1000,
- + .duplex = DUPLEX_FULL,
- + .bit = ETHTOOL_LINK_MODE_1000baseT_Full_BIT,
- + },
- + {
- + .speed = SPEED_1000,
- + .duplex = DUPLEX_HALF,
- + .bit = ETHTOOL_LINK_MODE_1000baseT_Half_BIT,
- + },
- + {
- + .speed = SPEED_100,
- + .duplex = DUPLEX_FULL,
- + .bit = ETHTOOL_LINK_MODE_100baseT_Full_BIT,
- + },
- + {
- + .speed = SPEED_100,
- + .duplex = DUPLEX_HALF,
- + .bit = ETHTOOL_LINK_MODE_100baseT_Half_BIT,
- + },
- + {
- + .speed = SPEED_10,
- + .duplex = DUPLEX_FULL,
- + .bit = ETHTOOL_LINK_MODE_10baseT_Full_BIT,
- + },
- + {
- + .speed = SPEED_10,
- + .duplex = DUPLEX_HALF,
- + .bit = ETHTOOL_LINK_MODE_10baseT_Half_BIT,
- + },
- +};
- +
- +/**
- + * phy_lookup_setting - lookup a PHY setting
- + * @speed: speed to match
- + * @duplex: duplex to match
- + * @mask: allowed link modes
- + * @maxbit: bit size of link modes
- + * @exact: an exact match is required
- + *
- + * Search the settings array for a setting that matches the speed and
- + * duplex, and which is supported.
- + *
- + * If @exact is unset, either an exact match or %NULL for no match will
- + * be returned.
- + *
- + * If @exact is set, an exact match, the fastest supported setting at
- + * or below the specified speed, the slowest supported setting, or if
- + * they all fail, %NULL will be returned.
- + */
- +const struct phy_setting *
- +phy_lookup_setting(int speed, int duplex, const unsigned long *mask,
- + size_t maxbit, bool exact)
- +{
- + const struct phy_setting *p, *match = NULL, *last = NULL;
- + int i;
- +
- + for (i = 0, p = settings; i < ARRAY_SIZE(settings); i++, p++) {
- + if (p->bit < maxbit && test_bit(p->bit, mask)) {
- + last = p;
- + if (p->speed == speed && p->duplex == duplex) {
- + /* Exact match for speed and duplex */
- + match = p;
- + break;
- + } else if (!exact) {
- + if (!match && p->speed <= speed)
- + /* Candidate */
- + match = p;
- +
- + if (p->speed < speed)
- + break;
- + }
- + }
- + }
- +
- + if (!match && !exact)
- + match = last;
- +
- + return match;
- +}
- +EXPORT_SYMBOL_GPL(phy_lookup_setting);
- +
- +size_t phy_speeds(unsigned int *speeds, size_t size,
- + unsigned long *mask, size_t maxbit)
- +{
- + size_t count;
- + int i;
- +
- + for (i = 0, count = 0; i < ARRAY_SIZE(settings) && count < size; i++)
- + if (settings[i].bit < maxbit &&
- + test_bit(settings[i].bit, mask) &&
- + (count == 0 || speeds[count - 1] != settings[i].speed))
- + speeds[count++] = settings[i].speed;
- +
- + return count;
- +}
- +
- static inline void mmd_phy_indirect(struct mii_bus *bus, int prtad, int devad,
- int addr)
- {
- --- a/include/linux/phy.h
- +++ b/include/linux/phy.h
- @@ -645,6 +645,21 @@ struct phy_fixup {
- const char *phy_speed_to_str(int speed);
- const char *phy_duplex_to_str(unsigned int duplex);
-
- +/* A structure for mapping a particular speed and duplex
- + * combination to a particular SUPPORTED and ADVERTISED value
- + */
- +struct phy_setting {
- + u32 speed;
- + u8 duplex;
- + u8 bit;
- +};
- +
- +const struct phy_setting *
- +phy_lookup_setting(int speed, int duplex, const unsigned long *mask,
- + size_t maxbit, bool exact);
- +size_t phy_speeds(unsigned int *speeds, size_t size,
- + unsigned long *mask, size_t maxbit);
- +
- /**
- * phy_read_mmd - Convenience function for reading a register
- * from an MMD on a given PHY.
|