Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/C/Linux/drivers/net/mdio/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 6 kB image not shown  

Quelle  mdio-mux.c   Sprache: C

 
// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) 2011, 2012 Cavium, Inc.
 */


#include <linux/device.h>
#include <linux/mdio-mux.h>
#include <linux/module.h>
#include <linux/of_mdio.h>
#include <linux/phy.h>
#include <linux/platform_device.h>

#define DRV_DESCRIPTION "MDIO bus multiplexer driver"

struct mdio_mux_child_bus;

struct mdio_mux_parent_bus {
 struct mii_bus *mii_bus;
 int current_child;
 int parent_id;
 void *switch_data;
 int (*switch_fn)(int current_child, int desired_child, void *data);

 /* List of our children linked through their next fields. */
 struct mdio_mux_child_bus *children;
};

struct mdio_mux_child_bus {
 struct mii_bus *mii_bus;
 struct mdio_mux_parent_bus *parent;
 struct mdio_mux_child_bus *next;
 int bus_number;
};

/*
 * The parent bus' lock is used to order access to the switch_fn.
 */

static int mdio_mux_read(struct mii_bus *bus, int phy_id, int regnum)
{
 struct mdio_mux_child_bus *cb = bus->priv;
 struct mdio_mux_parent_bus *pb = cb->parent;
 int r;

 mutex_lock_nested(&pb->mii_bus->mdio_lock, MDIO_MUTEX_MUX);
 r = pb->switch_fn(pb->current_child, cb->bus_number, pb->switch_data);
 if (r)
  goto out;

 pb->current_child = cb->bus_number;

 r = pb->mii_bus->read(pb->mii_bus, phy_id, regnum);
out:
 mutex_unlock(&pb->mii_bus->mdio_lock);

 return r;
}

static int mdio_mux_read_c45(struct mii_bus *bus, int phy_id, int dev_addr,
        int regnum)
{
 struct mdio_mux_child_bus *cb = bus->priv;
 struct mdio_mux_parent_bus *pb = cb->parent;
 int r;

 mutex_lock_nested(&pb->mii_bus->mdio_lock, MDIO_MUTEX_MUX);
 r = pb->switch_fn(pb->current_child, cb->bus_number, pb->switch_data);
 if (r)
  goto out;

 pb->current_child = cb->bus_number;

 r = pb->mii_bus->read_c45(pb->mii_bus, phy_id, dev_addr, regnum);
out:
 mutex_unlock(&pb->mii_bus->mdio_lock);

 return r;
}

/*
 * The parent bus' lock is used to order access to the switch_fn.
 */

static int mdio_mux_write(struct mii_bus *bus, int phy_id,
     int regnum, u16 val)
{
 struct mdio_mux_child_bus *cb = bus->priv;
 struct mdio_mux_parent_bus *pb = cb->parent;

 int r;

 mutex_lock_nested(&pb->mii_bus->mdio_lock, MDIO_MUTEX_MUX);
 r = pb->switch_fn(pb->current_child, cb->bus_number, pb->switch_data);
 if (r)
  goto out;

 pb->current_child = cb->bus_number;

 r = pb->mii_bus->write(pb->mii_bus, phy_id, regnum, val);
out:
 mutex_unlock(&pb->mii_bus->mdio_lock);

 return r;
}

static int mdio_mux_write_c45(struct mii_bus *bus, int phy_id, int dev_addr,
         int regnum, u16 val)
{
 struct mdio_mux_child_bus *cb = bus->priv;
 struct mdio_mux_parent_bus *pb = cb->parent;

 int r;

 mutex_lock_nested(&pb->mii_bus->mdio_lock, MDIO_MUTEX_MUX);
 r = pb->switch_fn(pb->current_child, cb->bus_number, pb->switch_data);
 if (r)
  goto out;

 pb->current_child = cb->bus_number;

 r = pb->mii_bus->write_c45(pb->mii_bus, phy_id, dev_addr, regnum, val);
out:
 mutex_unlock(&pb->mii_bus->mdio_lock);

 return r;
}

static int parent_count;

static void mdio_mux_uninit_children(struct mdio_mux_parent_bus *pb)
{
 struct mdio_mux_child_bus *cb = pb->children;

 while (cb) {
  mdiobus_unregister(cb->mii_bus);
  mdiobus_free(cb->mii_bus);
  cb = cb->next;
 }
}

int mdio_mux_init(struct device *dev,
    struct device_node *mux_node,
    int (*switch_fn)(int cur, int desired, void *data),
    void **mux_handle,
    void *data,
    struct mii_bus *mux_bus)
{
 struct device_node *parent_bus_node;
 struct device_node *child_bus_node;
 int r, ret_val;
 struct mii_bus *parent_bus;
 struct mdio_mux_parent_bus *pb;
 struct mdio_mux_child_bus *cb;

 if (!mux_node)
  return -ENODEV;

 if (!mux_bus) {
  parent_bus_node = of_parse_phandle(mux_node,
         "mdio-parent-bus", 0);

  if (!parent_bus_node)
   return -ENODEV;

  parent_bus = of_mdio_find_bus(parent_bus_node);
  if (!parent_bus) {
   ret_val = -EPROBE_DEFER;
   goto err_parent_bus;
  }
 } else {
  parent_bus_node = NULL;
  parent_bus = mux_bus;
  get_device(&parent_bus->dev);
 }

 pb = devm_kzalloc(dev, sizeof(*pb), GFP_KERNEL);
 if (!pb) {
  ret_val = -ENOMEM;
  goto err_pb_kz;
 }

 pb->switch_data = data;
 pb->switch_fn = switch_fn;
 pb->current_child = -1;
 pb->parent_id = parent_count++;
 pb->mii_bus = parent_bus;

 ret_val = -ENODEV;
 for_each_available_child_of_node(mux_node, child_bus_node) {
  int v;

  r = of_property_read_u32(child_bus_node, "reg", &v);
  if (r) {
   dev_err(dev,
    "Error: Failed to find reg for child %pOF: %pe\n",
    child_bus_node, ERR_PTR(r));
   continue;
  }

  cb = devm_kzalloc(dev, sizeof(*cb), GFP_KERNEL);
  if (!cb) {
   ret_val = -ENOMEM;
   goto err_loop;
  }
  cb->bus_number = v;
  cb->parent = pb;

  cb->mii_bus = mdiobus_alloc();
  if (!cb->mii_bus) {
   ret_val = -ENOMEM;
   goto err_loop;
  }
  cb->mii_bus->priv = cb;

  cb->mii_bus->name = "mdio_mux";
  snprintf(cb->mii_bus->id, MII_BUS_ID_SIZE, "%s-%x.%x",
    cb->mii_bus->name, pb->parent_id, v);
  cb->mii_bus->parent = dev;
  if (parent_bus->read)
   cb->mii_bus->read = mdio_mux_read;
  if (parent_bus->write)
   cb->mii_bus->write = mdio_mux_write;
  if (parent_bus->read_c45)
   cb->mii_bus->read_c45 = mdio_mux_read_c45;
  if (parent_bus->write_c45)
   cb->mii_bus->write_c45 = mdio_mux_write_c45;
  r = of_mdiobus_register(cb->mii_bus, child_bus_node);
  if (r) {
   mdiobus_free(cb->mii_bus);
   if (r == -EPROBE_DEFER) {
    ret_val = r;
    goto err_loop;
   }
   devm_kfree(dev, cb);
   dev_err(dev,
    "Error: Failed to register MDIO bus for child %pOF: %pe\n",
    child_bus_node, ERR_PTR(r));
  } else {
   cb->next = pb->children;
   pb->children = cb;
  }
 }
 if (pb->children) {
  *mux_handle = pb;
  return 0;
 }

 dev_err(dev, "Error: No acceptable child buses found\n");

err_loop:
 mdio_mux_uninit_children(pb);
 of_node_put(child_bus_node);
err_pb_kz:
 put_device(&parent_bus->dev);
err_parent_bus:
 of_node_put(parent_bus_node);
 return ret_val;
}
EXPORT_SYMBOL_GPL(mdio_mux_init);

void mdio_mux_uninit(void *mux_handle)
{
 struct mdio_mux_parent_bus *pb = mux_handle;

 mdio_mux_uninit_children(pb);
 put_device(&pb->mii_bus->dev);
}
EXPORT_SYMBOL_GPL(mdio_mux_uninit);

MODULE_DESCRIPTION(DRV_DESCRIPTION);
MODULE_AUTHOR("David Daney");
MODULE_LICENSE("GPL v2");

Messung V0.5
C=95 H=93 G=93

¤ Dauer der Verarbeitung: 0.3 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.