cregit-Linux how code gets into the kernel

Release 4.7 drivers/net/phy/mdio_bus.c

Directory: drivers/net/phy
/* MDIO Bus interface
 *
 * Author: Andy Fleming
 *
 * Copyright (c) 2004 Freescale Semiconductor, Inc.
 *
 * This program is free software; you can redistribute  it and/or modify it
 * under  the terms of  the GNU General  Public License as published by the
 * Free Software Foundation;  either version 2 of the  License, or (at your
 * option) any later version.
 *
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/unistd.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/of_device.h>
#include <linux/of_mdio.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/mii.h>
#include <linux/ethtool.h>
#include <linux/phy.h>
#include <linux/io.h>
#include <linux/uaccess.h>

#include <asm/irq.h>


int mdiobus_register_device(struct mdio_device *mdiodev) { if (mdiodev->bus->mdio_map[mdiodev->addr]) return -EBUSY; mdiodev->bus->mdio_map[mdiodev->addr] = mdiodev; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
andrew lunnandrew lunn43100.00%1100.00%
Total43100.00%1100.00%

EXPORT_SYMBOL(mdiobus_register_device);
int mdiobus_unregister_device(struct mdio_device *mdiodev) { if (mdiodev->bus->mdio_map[mdiodev->addr] != mdiodev) return -EINVAL; mdiodev->bus->mdio_map[mdiodev->addr] = NULL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
andrew lunnandrew lunn45100.00%1100.00%
Total45100.00%1100.00%

EXPORT_SYMBOL(mdiobus_unregister_device);
struct phy_device *mdiobus_get_phy(struct mii_bus *bus, int addr) { struct mdio_device *mdiodev = bus->mdio_map[addr]; if (!mdiodev) return NULL; if (!(mdiodev->flags & MDIO_DEVICE_FLAG_PHY)) return NULL; return container_of(mdiodev, struct phy_device, mdio); }

Contributors

PersonTokensPropCommitsCommitProp
andrew lunnandrew lunn60100.00%1100.00%
Total60100.00%1100.00%

EXPORT_SYMBOL(mdiobus_get_phy);
bool mdiobus_is_registered_device(struct mii_bus *bus, int addr) { return bus->mdio_map[addr]; }

Contributors

PersonTokensPropCommitsCommitProp
andrew lunnandrew lunn21100.00%1100.00%
Total21100.00%1100.00%

EXPORT_SYMBOL(mdiobus_is_registered_device); /** * mdiobus_alloc_size - allocate a mii_bus structure * @size: extra amount of memory to allocate for private storage. * If non-zero, then bus->priv is points to that memory. * * Description: called by a bus driver to allocate an mii_bus * structure to fill in. */
struct mii_bus *mdiobus_alloc_size(size_t size) { struct mii_bus *bus; size_t aligned_size = ALIGN(sizeof(*bus), NETDEV_ALIGN); size_t alloc_size; int i; /* If we alloc extra space, it should be aligned */ if (size) alloc_size = aligned_size + size; else alloc_size = sizeof(*bus); bus = kzalloc(alloc_size, GFP_KERNEL); if (!bus) return NULL; bus->state = MDIOBUS_ALLOCATED; if (size) bus->priv = (void *)bus + aligned_size; /* Initialise the interrupts to polling */ for (i = 0; i < PHY_MAX_ADDR; i++) bus->irq[i] = PHY_POLL; return bus; }

Contributors

PersonTokensPropCommitsCommitProp
timur tabitimur tabi5445.00%120.00%
lennert buytenheklennert buytenhek3630.00%240.00%
andrew lunnandrew lunn2621.67%120.00%
dan carpenterdan carpenter43.33%120.00%
Total120100.00%5100.00%

EXPORT_SYMBOL(mdiobus_alloc_size);
static void _devm_mdiobus_free(struct device *dev, void *res) { mdiobus_free(*(struct mii_bus **)res); }

Contributors

PersonTokensPropCommitsCommitProp
grygorii strashkogrygorii strashko27100.00%1100.00%
Total27100.00%1100.00%


static int devm_mdiobus_match(struct device *dev, void *res, void *data) { struct mii_bus **r = res; if (WARN_ON(!r || !*r)) return 0; return *r == data; }

Contributors

PersonTokensPropCommitsCommitProp
grygorii strashkogrygorii strashko48100.00%1100.00%
Total48100.00%1100.00%

/** * devm_mdiobus_alloc_size - Resource-managed mdiobus_alloc_size() * @dev: Device to allocate mii_bus for * @sizeof_priv: Space to allocate for private structure. * * Managed mdiobus_alloc_size. mii_bus allocated with this function is * automatically freed on driver detach. * * If an mii_bus allocated with this function needs to be freed separately, * devm_mdiobus_free() must be used. * * RETURNS: * Pointer to allocated mii_bus on success, NULL on failure. */
struct mii_bus *devm_mdiobus_alloc_size(struct device *dev, int sizeof_priv) { struct mii_bus **ptr, *bus; ptr = devres_alloc(_devm_mdiobus_free, sizeof(*ptr), GFP_KERNEL); if (!ptr) return NULL; /* use raw alloc_dr for kmalloc caller tracing */ bus = mdiobus_alloc_size(sizeof_priv); if (bus) { *ptr = bus; devres_add(dev, ptr); } else { devres_free(ptr); } return bus; }

Contributors

PersonTokensPropCommitsCommitProp
grygorii strashkogrygorii strashko84100.00%1100.00%
Total84100.00%1100.00%

EXPORT_SYMBOL_GPL(devm_mdiobus_alloc_size); /** * devm_mdiobus_free - Resource-managed mdiobus_free() * @dev: Device this mii_bus belongs to * @bus: the mii_bus associated with the device * * Free mii_bus allocated with devm_mdiobus_alloc_size(). */
void devm_mdiobus_free(struct device *dev, struct mii_bus *bus) { int rc; rc = devres_release(dev, _devm_mdiobus_free, devm_mdiobus_match, bus); WARN_ON(rc); }

Contributors

PersonTokensPropCommitsCommitProp
grygorii strashkogrygorii strashko36100.00%1100.00%
Total36100.00%1100.00%

EXPORT_SYMBOL_GPL(devm_mdiobus_free); /** * mdiobus_release - mii_bus device release callback * @d: the target struct device that contains the mii_bus * * Description: called when the last reference to an mii_bus is * dropped, to free the underlying memory. */
static void mdiobus_release(struct device *d) { struct mii_bus *bus = to_mii_bus(d); BUG_ON(bus->state != MDIOBUS_RELEASED && /* for compatibility with error handling in drivers */ bus->state != MDIOBUS_ALLOCATED); kfree(bus); }

Contributors

PersonTokensPropCommitsCommitProp
lennert buytenheklennert buytenhek3583.33%150.00%
krzysztof halasakrzysztof halasa716.67%150.00%
Total42100.00%2100.00%

static struct class mdio_bus_class = { .name = "mdio_bus", .dev_release = mdiobus_release, }; #if IS_ENABLED(CONFIG_OF_MDIO) /* Helper function for of_mdio_find_bus */
static int of_mdio_bus_match(struct device *dev, const void *mdio_bus_np) { return dev->of_node == mdio_bus_np; }

Contributors

PersonTokensPropCommitsCommitProp
david daneydavid daney2295.65%150.00%
michal miroslawmichal miroslaw14.35%150.00%
Total23100.00%2100.00%

/** * of_mdio_find_bus - Given an mii_bus node, find the mii_bus. * @mdio_bus_np: Pointer to the mii_bus. * * Returns a reference to the mii_bus, or NULL if none found. The * embedded struct device will have its reference count incremented, * and this must be put once the bus is finished with. * * Because the association of a device_node and mii_bus is made via * of_mdiobus_register(), the mii_bus cannot be found before it is * registered with of_mdiobus_register(). * */
struct mii_bus *of_mdio_find_bus(struct device_node *mdio_bus_np) { struct device *d; if (!mdio_bus_np) return NULL; d = class_find_device(&mdio_bus_class, NULL, mdio_bus_np, of_mdio_bus_match); return d ? to_mii_bus(d) : NULL; }

Contributors

PersonTokensPropCommitsCommitProp
david daneydavid daney49100.00%1100.00%
Total49100.00%1100.00%

EXPORT_SYMBOL(of_mdio_find_bus); /* Walk the list of subnodes of a mdio bus and look for a node that * matches the mdio device's address with its 'reg' property. If * found, set the of_node pointer for the mdio device. This allows * auto-probed phy devices to be supplied with information passed in * via DT. */
static void of_mdiobus_link_mdiodev(struct mii_bus *bus, struct mdio_device *mdiodev) { struct device *dev = &mdiodev->dev; struct device_node *child; if (dev->of_node || !bus->dev.of_node) return; for_each_available_child_of_node(bus->dev.of_node, child) { int addr; int ret; ret = of_property_read_u32(child, "reg", &addr); if (ret < 0) { dev_err(dev, "%s has invalid MDIO address\n", child->full_name); continue; } /* A MDIO device must have a reg property in the range [0-31] */ if (addr >= PHY_MAX_ADDR) { dev_err(dev, "%s MDIO address %i is too large\n", child->full_name, addr); continue; } if (addr == mdiodev->addr) { dev->of_node = child; return; } } }

Contributors

PersonTokensPropCommitsCommitProp
daniel mackdaniel mack12091.60%133.33%
andrew lunnandrew lunn118.40%266.67%
Total131100.00%3100.00%

#else /* !IS_ENABLED(CONFIG_OF_MDIO) */
static inline void of_mdiobus_link_mdiodev(struct mii_bus *mdio, struct mdio_device *mdiodev) { }

Contributors

PersonTokensPropCommitsCommitProp
daniel mackdaniel mack1381.25%150.00%
andrew lunnandrew lunn318.75%150.00%
Total16100.00%2100.00%

#endif /** * __mdiobus_register - bring up all the PHYs on a given bus and attach them to bus * @bus: target mii_bus * @owner: module containing bus accessor functions * * Description: Called by a bus driver to bring up all the PHYs * on a given bus, and attach them to the bus. Drivers should use * mdiobus_register() rather than __mdiobus_register() unless they * need to pass a specific owner module. MDIO devices which are not * PHYs will not be brought up by this function. They are expected to * to be explicitly listed in DT and instantiated by of_mdiobus_register(). * * Returns 0 on success or < 0 on error. */
int __mdiobus_register(struct mii_bus *bus, struct module *owner) { struct mdio_device *mdiodev; int i, err; if (NULL == bus || NULL == bus->name || NULL == bus->read || NULL == bus->write) return -EINVAL; BUG_ON(bus->state != MDIOBUS_ALLOCATED && bus->state != MDIOBUS_UNREGISTERED); bus->owner = owner; bus->dev.parent = bus->parent; bus->dev.class = &mdio_bus_class; bus->dev.groups = NULL; dev_set_name(&bus->dev, "%s", bus->id); err = device_register(&bus->dev); if (err) { pr_err("mii_bus %s failed to register\n", bus->id); put_device(&bus->dev); return -EINVAL; } mutex_init(&bus->mdio_lock); if (bus->reset) bus->reset(bus); for (i = 0; i < PHY_MAX_ADDR; i++) { if ((bus->phy_mask & (1 << i)) == 0) { struct phy_device *phydev; phydev = mdiobus_scan(bus, i); if (IS_ERR(phydev) && (PTR_ERR(phydev) != -ENODEV)) { err = PTR_ERR(phydev); goto error; } } } bus->state = MDIOBUS_REGISTERED; pr_info("%s: probed\n", bus->name); return 0; error: while (--i >= 0) { mdiodev = bus->mdio_map[i]; if (!mdiodev) continue; mdiodev->device_remove(mdiodev); mdiodev->device_free(mdiodev); } device_del(&bus->dev); return err; }

Contributors

PersonTokensPropCommitsCommitProp
lennert buytenheklennert buytenhek12739.94%212.50%
andy flemingandy fleming6721.07%16.25%
krzysztof halasakrzysztof halasa4012.58%212.50%
andrew lunnandrew lunn237.23%16.25%
russell kingrussell king175.35%212.50%
matt portermatt porter123.77%16.25%
marek vasutmarek vasut103.14%16.25%
levente kurusalevente kurusa82.52%16.25%
adrian bunkadrian bunk82.52%16.25%
stephen hemmingerstephen hemminger20.63%16.25%
kay sieverskay sievers20.63%16.25%
joe perchesjoe perches10.31%16.25%
herbert valerio riedelherbert valerio riedel10.31%16.25%
Total318100.00%16100.00%

EXPORT_SYMBOL(__mdiobus_register);
void mdiobus_unregister(struct mii_bus *bus) { struct mdio_device *mdiodev; int i; BUG_ON(bus->state != MDIOBUS_REGISTERED); bus->state = MDIOBUS_UNREGISTERED; for (i = 0; i < PHY_MAX_ADDR; i++) { mdiodev = bus->mdio_map[i]; if (!mdiodev) continue; mdiodev->device_remove(mdiodev); mdiodev->device_free(mdiodev); } device_del(&bus->dev); }

Contributors

PersonTokensPropCommitsCommitProp
lennert buytenheklennert buytenhek4249.41%225.00%
andrew lunnandrew lunn2934.12%225.00%
mark saltermark salter89.41%112.50%
russell kingrussell king33.53%112.50%
herbert valerio riedelherbert valerio riedel22.35%112.50%
grant likelygrant likely11.18%112.50%
Total85100.00%8100.00%

EXPORT_SYMBOL(mdiobus_unregister); /** * mdiobus_free - free a struct mii_bus * @bus: mii_bus to free * * This function releases the reference to the underlying device * object in the mii_bus. If this is the last reference, the mii_bus * will be freed. */
void mdiobus_free(struct mii_bus *bus) { /* For compatibility with error handling in drivers. */ if (bus->state == MDIOBUS_ALLOCATED) { kfree(bus); return; } BUG_ON(bus->state != MDIOBUS_UNREGISTERED); bus->state = MDIOBUS_RELEASED; put_device(&bus->dev); }

Contributors

PersonTokensPropCommitsCommitProp
lennert buytenheklennert buytenhek4998.00%266.67%
sergei shtylyovsergei shtylyov12.00%133.33%
Total50100.00%3100.00%

EXPORT_SYMBOL(mdiobus_free); /** * mdiobus_scan - scan a bus for MDIO devices. * @bus: mii_bus to scan * @addr: address on bus to scan * * This function scans the MDIO bus, looking for devices which can be * identified using a vendor/product ID in registers 2 and 3. Not all * MDIO devices have such registers, but PHY devices typically * do. Hence this function assumes anything found is a PHY, or can be * treated as a PHY. Other MDIO devices, such as switches, will * probably not be found during the scan. */
struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr) { struct phy_device *phydev; int err; phydev = get_phy_device(bus, addr, false); if (IS_ERR(phydev)) return phydev; /* * For DT, see if the auto-probed phy has a correspoding child * in the bus node, and set the of_node pointer in this case. */ of_mdiobus_link_mdiodev(bus, &phydev->mdio); err = phy_device_register(phydev); if (err) { phy_device_free(phydev); return ERR_PTR(-ENODEV); } return phydev; }

Contributors

PersonTokensPropCommitsCommitProp
andy flemingandy fleming3137.35%112.50%
lennert buytenheklennert buytenhek2428.92%112.50%
daniel mackdaniel mack78.43%112.50%
anton vorontsovanton vorontsov78.43%112.50%
sergei shtylyovsergei shtylyov56.02%112.50%
andrew lunnandrew lunn44.82%112.50%
grant likelygrant likely33.61%112.50%
david daneydavid daney22.41%112.50%
Total83100.00%8100.00%

EXPORT_SYMBOL(mdiobus_scan); /** * mdiobus_read_nested - Nested version of the mdiobus_read function * @bus: the mii_bus struct * @addr: the phy address * @regnum: register number to read * * In case of nested MDIO bus access avoid lockdep false positives by * using mutex_lock_nested(). * * NOTE: MUST NOT be called from interrupt context, * because the bus read/write functions may wait for an interrupt * to conclude the operation. */
int mdiobus_read_nested(struct mii_bus *bus, int addr, u32 regnum) { int retval; BUG_ON(in_interrupt()); mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); retval = bus->read(bus, addr, regnum); mutex_unlock(&bus->mdio_lock); return retval; }

Contributors

PersonTokensPropCommitsCommitProp
neil armstrongneil armstrong5898.31%150.00%
andrew lunnandrew lunn11.69%150.00%
Total59100.00%2100.00%

EXPORT_SYMBOL(mdiobus_read_nested); /** * mdiobus_read - Convenience function for reading a given MII mgmt register * @bus: the mii_bus struct * @addr: the phy address * @regnum: register number to read * * NOTE: MUST NOT be called from interrupt context, * because the bus read/write functions may wait for an interrupt * to conclude the operation. */
int mdiobus_read(struct mii_bus *bus, int addr, u32 regnum) { int retval; BUG_ON(in_interrupt()); mutex_lock(&bus->mdio_lock); retval = bus->read(bus, addr, regnum); mutex_unlock(&bus->mdio_lock); return retval; }

Contributors

PersonTokensPropCommitsCommitProp
lennert buytenheklennert buytenhek5698.25%150.00%
jason gunthorpejason gunthorpe11.75%150.00%
Total57100.00%2100.00%

EXPORT_SYMBOL(mdiobus_read); /** * mdiobus_write_nested - Nested version of the mdiobus_write function * @bus: the mii_bus struct * @addr: the phy address * @regnum: register number to write * @val: value to write to @regnum * * In case of nested MDIO bus access avoid lockdep false positives by * using mutex_lock_nested(). * * NOTE: MUST NOT be called from interrupt context, * because the bus read/write functions may wait for an interrupt * to conclude the operation. */
int mdiobus_write_nested(struct mii_bus *bus, int addr, u32 regnum, u16 val) { int err; BUG_ON(in_interrupt()); mutex_lock_nested(&bus->mdio_lock, MDIO_MUTEX_NESTED); err = bus->write(bus, addr, regnum, val); mutex_unlock(&bus->mdio_lock); return err; }

Contributors

PersonTokensPropCommitsCommitProp
neil armstrongneil armstrong6398.44%150.00%
andrew lunnandrew lunn11.56%150.00%
Total64100.00%2100.00%

EXPORT_SYMBOL(mdiobus_write_nested); /** * mdiobus_write - Convenience function for writing a given MII mgmt register * @bus: the mii_bus struct * @addr: the phy address * @regnum: register number to write * @val: value to write to @regnum * * NOTE: MUST NOT be called from interrupt context, * because the bus read/write functions may wait for an interrupt * to conclude the operation. */
int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val) { int err; BUG_ON(in_interrupt()); mutex_lock(&bus->mdio_lock); err = bus->write(bus, addr, regnum, val); mutex_unlock(&bus->mdio_lock); return err; }

Contributors

PersonTokensPropCommitsCommitProp
lennert buytenheklennert buytenhek6198.39%150.00%
jason gunthorpejason gunthorpe11.61%150.00%
Total62100.00%2100.00%

EXPORT_SYMBOL(mdiobus_write); /** * mdio_bus_match - determine if given MDIO driver supports the given * MDIO device * @dev: target MDIO device * @drv: given MDIO driver * * Description: Given a MDIO device, and a MDIO driver, return 1 if * the driver supports the device. Otherwise, return 0. This may * require calling the devices own match function, since different classes * of MDIO devices have different match criteria. */
static int mdio_bus_match(struct device *dev, struct device_driver *drv) { struct mdio_device *mdio = to_mdio_device(dev); if (of_driver_match_device(dev, drv)) return 1; if (mdio->bus_match) return mdio->bus_match(dev, drv); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
andy flemingandy fleming2238.60%125.00%
david daneydavid daney2136.84%125.00%
andrew lunnandrew lunn1017.54%125.00%
shaohui xieshaohui xie47.02%125.00%
Total57100.00%4100.00%

#ifdef CONFIG_PM
static int mdio_bus_suspend(struct device *dev) { struct mdio_device *mdio = to_mdio_device(dev); if (mdio->pm_ops && mdio->pm_ops->suspend) return mdio->pm_ops->suspend(dev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
andrew lunnandrew lunn1736.96%120.00%
anton vorontsovanton vorontsov1736.96%240.00%
andy flemingandy fleming1021.74%120.00%
simon guinotsimon guinot24.35%120.00%
Total46100.00%5100.00%


static int mdio_bus_resume(struct device *dev) { struct mdio_device *mdio = to_mdio_device(dev); if (mdio->pm_ops && mdio->pm_ops->resume) return mdio->pm_ops->resume(dev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
anton vorontsovanton vorontsov1941.30%233.33%
andrew lunnandrew lunn1736.96%116.67%
giuseppe cavallarogiuseppe cavallaro613.04%116.67%
andy flemingandy fleming24.35%116.67%
simon guinotsimon guinot24.35%116.67%
Total46100.00%6100.00%


static int mdio_bus_restore(struct device *dev) { struct mdio_device *mdio = to_mdio_device(dev); if (mdio->pm_ops && mdio->pm_ops->restore) return mdio->pm_ops->restore(dev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
anton vorontsovanton vorontsov2963.04%150.00%
andrew lunnandrew lunn1736.96%150.00%
Total46100.00%2100.00%

static const struct dev_pm_ops mdio_bus_pm_ops = { .suspend = mdio_bus_suspend, .resume = mdio_bus_resume, .freeze = mdio_bus_suspend, .thaw = mdio_bus_resume, .restore = mdio_bus_restore, }; #define MDIO_BUS_PM_OPS (&mdio_bus_pm_ops) #else #define MDIO_BUS_PM_OPS NULL #endif /* CONFIG_PM */ struct bus_type mdio_bus_type = { .name = "mdio_bus", .match = mdio_bus_match, .pm = MDIO_BUS_PM_OPS, }; EXPORT_SYMBOL(mdio_bus_type);
int __init mdio_bus_init(void) { int ret; ret = class_register(&mdio_bus_class); if (!ret) { ret = bus_register(&mdio_bus_type); if (ret) class_unregister(&mdio_bus_class); } return ret; }

Contributors

PersonTokensPropCommitsCommitProp
lennert buytenheklennert buytenhek3370.21%150.00%
andy flemingandy fleming1429.79%150.00%
Total47100.00%2100.00%


void mdio_bus_exit(void) { class_unregister(&mdio_bus_class); bus_unregister(&mdio_bus_type); }

Contributors

PersonTokensPropCommitsCommitProp
andy flemingandy fleming1368.42%150.00%
lennert buytenheklennert buytenhek631.58%150.00%
Total19100.00%2100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
lennert buytenheklennert buytenhek51825.16%47.02%
andrew lunnandrew lunn35217.10%1017.54%
andy flemingandy fleming23911.61%23.51%
grygorii strashkogrygorii strashko20610.00%11.75%
daniel mackdaniel mack1436.95%23.51%
neil armstrongneil armstrong1336.46%11.75%
anton vorontsovanton vorontsov1256.07%47.02%
david daneydavid daney1065.15%35.26%
timur tabitimur tabi552.67%11.75%
krzysztof halasakrzysztof halasa472.28%23.51%
russell kingrussell king221.07%35.26%
matt portermatt porter120.58%11.75%
sergei shtylyovsergei shtylyov110.53%23.51%
marek vasutmarek vasut100.49%11.75%
mark saltermark salter80.39%11.75%
levente kurusalevente kurusa80.39%11.75%
adrian bunkadrian bunk80.39%11.75%
joe perchesjoe perches80.39%11.75%
giuseppe cavallarogiuseppe cavallaro60.29%11.75%
bjorn morkbjorn mork50.24%11.75%
vitaly bordugvitaly bordug50.24%11.75%
grant likelygrant likely40.19%11.75%
shaohui xieshaohui xie40.19%11.75%
dan carpenterdan carpenter40.19%11.75%
simon guinotsimon guinot40.19%11.75%
mark brownmark brown30.15%11.75%
herbert valerio riedelherbert valerio riedel30.15%11.75%
stephen hemmingerstephen hemminger20.10%11.75%
jason gunthorpejason gunthorpe20.10%11.75%
kay sieverskay sievers20.10%11.75%
randy dunlaprandy dunlap20.10%23.51%
arnd bergmannarnd bergmann10.05%11.75%
michal miroslawmichal miroslaw10.05%11.75%
Total2059100.00%57100.00%
Directory: drivers/net/phy
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}