Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F174407275
D58258.id186422.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
19 KB
Referenced Files
None
Subscribers
None
D58258.id186422.diff
View Options
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -3145,6 +3145,7 @@
dev/sdio/sdio_subr.c optional mmccam
dev/sdio/sdiob.c optional mmccam
dev/sff/sff_if.m optional sff
+dev/sff/sff.c optional sff
dev/sff/sfp_fdt.c optional sff fdt
dev/sge/if_sge.c optional sge pci
dev/siis/siis.c optional siis pci
Index: sys/dev/dpaa2/dpaa2_mc_fdt.c
===================================================================
--- sys/dev/dpaa2/dpaa2_mc_fdt.c
+++ sys/dev/dpaa2/dpaa2_mc_fdt.c
@@ -193,6 +193,27 @@
return (OF_device_from_xref(OF_xref_from_node(sc->phy_handle)));
}
+/*
+ * Resolve the "sff,sfp" device for this DPMAC from the "sfp" phandle parsed at
+ * attach. The sff(4) driver (sfp_fdt) registers itself by the referenced node's
+ * xref, so a simple xref lookup yields its device_t. Returns NULL if the DPMAC
+ * has no SFP association or the sff device is not (yet) attached.
+ */
+static device_t
+dpaa2_mac_fdt_get_sff_dev(device_t dev)
+{
+ struct dpaa2_mac_fdt_softc *sc;
+
+ if (dev == NULL)
+ return (NULL);
+
+ sc = device_get_softc(dev);
+ if (sc->sfp == 0)
+ return (NULL);
+
+ return (OF_device_from_xref(OF_xref_from_node(sc->sfp)));
+}
+
static device_method_t dpaa2_mac_fdt_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, dpaa2_mac_dev_probe),
@@ -342,6 +363,30 @@
return (0);
}
+static int
+dpaa2_mc_fdt_get_sff_dev(device_t dev, device_t *sff_dev, uint32_t id)
+{
+ device_t mdev, sffdev;
+
+ mdev = dpaa2_mc_fdt_find_dpaa2_mac_dev(dev, id);
+ if (mdev == NULL)
+ return (ENXIO);
+
+ sffdev = dpaa2_mac_fdt_get_sff_dev(mdev);
+ if (sffdev == NULL)
+ return (ENXIO);
+
+ if (sff_dev != NULL)
+ *sff_dev = sffdev;
+
+ if (bootverbose)
+ device_printf(dev, "dpmac_id %u mdev %s sff dev %s\n",
+ id, device_get_nameunit(mdev),
+ device_get_nameunit(sffdev));
+
+ return (0);
+}
+
static const struct ofw_bus_devinfo *
dpaa2_mc_simplebus_get_devinfo(device_t bus, device_t child)
{
@@ -379,6 +424,7 @@
DEVMETHOD(dpaa2_mc_reserve_dev, dpaa2_mc_reserve_dev),
DEVMETHOD(dpaa2_mc_release_dev, dpaa2_mc_release_dev),
DEVMETHOD(dpaa2_mc_get_phy_dev, dpaa2_mc_fdt_get_phy_dev),
+ DEVMETHOD(dpaa2_mc_get_sff_dev, dpaa2_mc_fdt_get_sff_dev),
/* OFW/simplebus */
DEVMETHOD(ofw_bus_get_devinfo, dpaa2_mc_simplebus_get_devinfo),
Index: sys/dev/dpaa2/dpaa2_mc_if.m
===================================================================
--- sys/dev/dpaa2/dpaa2_mc_if.m
+++ sys/dev/dpaa2/dpaa2_mc_if.m
@@ -106,6 +106,15 @@
phy_dev, id));
return (ENXIO);
}
+
+ static int
+ bypass_get_sff_dev(device_t dev, device_t *sff_dev, uint32_t id)
+ {
+ if (device_get_parent(dev) != NULL)
+ return (DPAA2_MC_GET_SFF_DEV(device_get_parent(dev),
+ sff_dev, id));
+ return (ENXIO);
+ }
}
METHOD int manage_dev {
@@ -150,3 +159,21 @@
device_t *phy_dev;
uint32_t id;
} DEFAULT bypass_get_phy_dev;
+
+/**
+ * @brief Look up the "sff,sfp" device associated with a DPMAC.
+ *
+ * Resolved from the "sfp" phandle in the DPMAC's device-tree node (the sff(4)
+ * driver registers itself by that node's xref). Only implemented on the FDT
+ * compat layer; returns ENXIO under ACPI, where firmware provides no such
+ * association.
+ *
+ * dev - requesting device (walked up to the MC bus)
+ * sff_dev - the sff,sfp transceiver device (call SFF_READ_EEPROM() on it)
+ * id - DPMAC object id
+ */
+METHOD int get_sff_dev {
+ device_t dev;
+ device_t *sff_dev;
+ uint32_t id;
+} DEFAULT bypass_get_sff_dev;
Index: sys/dev/dpaa2/dpaa2_ni.c
===================================================================
--- sys/dev/dpaa2/dpaa2_ni.c
+++ sys/dev/dpaa2/dpaa2_ni.c
@@ -79,6 +79,7 @@
#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>
#include <dev/mdio/mdio.h>
+#include <dev/sff/sff.h>
#include "opt_acpi.h"
#include "opt_platform.h"
@@ -95,6 +96,7 @@
#include "dpaa2_swp.h"
#include "dpaa2_swp_if.h"
#include "dpaa2_cmd_if.h"
+#include "sff_if.h"
#include "dpaa2_ni.h"
#include "dpaa2_channel.h"
#include "dpaa2_buf.h"
@@ -2565,44 +2567,163 @@
if_qflush(ifp);
}
+/*
+ * SFP+ EEPROM access for SIOCGI2C, so "ifconfig -v <dpni>" can show the
+ * module's SFF-8472 identity and diagnostics. The module EEPROM lives on an
+ * i2c bus reached in one of two ways:
+ *
+ * - FDT: the DPMAC's device-tree node has an "sfp" phandle to an "sff,sfp"
+ * node handled by sff(4). DPAA2_MC_GET_SFF_DEV() returns that device and
+ * SFF_READ_EEPROM() performs the read (the i2c mux, if any, is switched
+ * transparently by the i2c framework).
+ *
+ * - ACPI: firmware exposes no such association, so it is supplied per
+ * interface by loader tunables and any i2c mux is switched explicitly via
+ * the sff(4) helper sff_read_eeprom():
+ * hw.dpaa2.dpni<unit>.sfp_bus iicbus unit (e.g. 0 for iic0); <0 disabled
+ * hw.dpaa2.dpni<unit>.sfp_mux 7-bit i2c mux address (e.g. 0x77); 0 none
+ * hw.dpaa2.dpni<unit>.sfp_chan mux channel the cage sits on
+ * hw.dpaa2.dpni<unit>.sfp_type 0 = PCA9547 (sel 0x08|ch), 1 = PCA9548
+ */
+#define DPAA2_SFP_MUX_9547 0
+#define DPAA2_SFP_MUX_9548 1
+
static int
-dpaa2_ni_ioctl(if_t ifp, u_long c, caddr_t data)
+dpaa2_ni_sfp_ioctl(struct dpaa2_ni_softc *sc, struct ifreq *ifr)
+{
+ struct ifi2creq req;
+ device_t sffdev = NULL, requester;
+ char tname[64];
+ int unit, busunit, mux, chan, type, error;
+ uint8_t chsel, chrestore;
+
+ error = copyin(ifr_data_get_ptr(ifr), &req, sizeof(req));
+ if (error != 0)
+ return (error);
+ if (req.dev_addr != 0xa0 && req.dev_addr != 0xa2)
+ return (EINVAL);
+ if (req.len == 0 || req.len > (int)sizeof(req.data))
+ return (EINVAL);
+ if ((u_int)req.offset + req.len > 256)
+ return (EINVAL);
+
+ /*
+ * Primary path: the DPMAC's device tree names an sff,sfp device; let
+ * sff(4) do the read (it switches the i2c mux transparently).
+ */
+ if (DPAA2_MC_GET_SFF_DEV(sc->dev, &sffdev, sc->mac.dpmac_id) == 0 &&
+ sffdev != NULL) {
+ error = SFF_READ_EEPROM(sffdev, req.dev_addr, req.offset,
+ req.data, req.len);
+ if (error != 0)
+ return (error);
+ return (copyout(&req, ifr_data_get_ptr(ifr), sizeof(req)));
+ }
+
+ /*
+ * Fallback: no sff,sfp device (e.g. ACPI boot). Take the association
+ * from the per-interface loader tunables and drive the mux explicitly
+ * via the sff(4) helper.
+ */
+ busunit = -1;
+ mux = 0;
+ chan = 0;
+ type = DPAA2_SFP_MUX_9547;
+ unit = device_get_unit(sc->dev);
+ snprintf(tname, sizeof(tname), "hw.dpaa2.dpni%d.sfp_bus", unit);
+ TUNABLE_INT_FETCH(tname, &busunit);
+ if (busunit < 0)
+ return (ENXIO);
+ snprintf(tname, sizeof(tname), "hw.dpaa2.dpni%d.sfp_mux", unit);
+ TUNABLE_INT_FETCH(tname, &mux);
+ snprintf(tname, sizeof(tname), "hw.dpaa2.dpni%d.sfp_chan", unit);
+ TUNABLE_INT_FETCH(tname, &chan);
+ snprintf(tname, sizeof(tname), "hw.dpaa2.dpni%d.sfp_type", unit);
+ TUNABLE_INT_FETCH(tname, &type);
+
+ requester = devclass_get_device(devclass_find("iic"), busunit);
+ if (requester == NULL)
+ return (ENXIO);
+ if (type == DPAA2_SFP_MUX_9548) {
+ chsel = (uint8_t)(1u << (chan & 0x07));
+ chrestore = 0x00; /* all channels off */
+ } else {
+ chsel = (uint8_t)(0x08 | (chan & 0x07)); /* 9547 enable|ch */
+ chrestore = 0x08; /* power-on value (ch0) */
+ }
+
+ error = sff_read_eeprom(requester, mux, chsel, chrestore,
+ req.dev_addr, req.offset, req.data, req.len);
+ if (error != 0)
+ return (error);
+
+ return (copyout(&req, ifr_data_get_ptr(ifr), sizeof(req)));
+}
+
+/*
+ * Open/close the resource container (RC) and network interface (NI) MC objects.
+ * Only ioctls that actually issue MC commands need these, so they are opened on
+ * demand rather than around the whole switch.
+ */
+static int
+dpaa2_ni_cmd_open(struct dpaa2_ni_softc *sc, struct dpaa2_cmd *cmd,
+ uint16_t *rc_token, uint16_t *ni_token)
{
- struct dpaa2_ni_softc *sc = if_getsoftc(ifp);
- struct ifreq *ifr = (struct ifreq *) data;
device_t pdev = device_get_parent(sc->dev);
device_t dev = sc->dev;
- device_t child = dev;
struct dpaa2_devinfo *rcinfo = device_get_ivars(pdev);
struct dpaa2_devinfo *dinfo = device_get_ivars(dev);
- struct dpaa2_cmd cmd;
- uint32_t changed = 0;
- uint16_t rc_token, ni_token;
- int mtu, error, rc = 0;
+ int error;
- DPAA2_CMD_INIT(&cmd);
+ DPAA2_CMD_INIT(cmd);
- error = DPAA2_CMD_RC_OPEN(dev, child, &cmd, rcinfo->id, &rc_token);
+ error = DPAA2_CMD_RC_OPEN(dev, dev, cmd, rcinfo->id, rc_token);
if (error) {
device_printf(dev, "%s: failed to open resource container: "
"id=%d, error=%d\n", __func__, rcinfo->id, error);
- goto err_exit;
+ return (error);
}
- error = DPAA2_CMD_NI_OPEN(dev, child, &cmd, dinfo->id, &ni_token);
+ error = DPAA2_CMD_NI_OPEN(dev, dev, cmd, dinfo->id, ni_token);
if (error) {
device_printf(dev, "%s: failed to open network interface: "
"id=%d, error=%d\n", __func__, dinfo->id, error);
- goto close_rc;
+ (void)DPAA2_CMD_RC_CLOSE(dev, dev, DPAA2_CMD_TK(cmd, *rc_token));
+ return (error);
}
+ return (0);
+}
+
+static void
+dpaa2_ni_cmd_close(struct dpaa2_ni_softc *sc, struct dpaa2_cmd *cmd,
+ uint16_t rc_token, uint16_t ni_token)
+{
+ device_t dev = sc->dev;
+
+ (void)DPAA2_CMD_NI_CLOSE(dev, dev, DPAA2_CMD_TK(cmd, ni_token));
+ (void)DPAA2_CMD_RC_CLOSE(dev, dev, DPAA2_CMD_TK(cmd, rc_token));
+}
+
+static int
+dpaa2_ni_ioctl(if_t ifp, u_long c, caddr_t data)
+{
+ struct dpaa2_ni_softc *sc = if_getsoftc(ifp);
+ struct ifreq *ifr = (struct ifreq *) data;
+ device_t dev = sc->dev;
+ uint32_t changed = 0;
+ int rc = 0;
switch (c) {
- case SIOCSIFMTU:
+ case SIOCSIFMTU: {
+ struct dpaa2_cmd cmd;
+ uint16_t rc_token, ni_token;
+ int mtu;
+
DPNI_LOCK(sc);
mtu = ifr->ifr_mtu;
if (mtu < ETHERMIN || mtu > ETHERMTU_JUMBO) {
DPNI_UNLOCK(sc);
- error = EINVAL;
- goto close_ni;
+ rc = EINVAL;
+ break;
}
if_setmtu(ifp, mtu);
DPNI_UNLOCK(sc);
@@ -2611,12 +2732,20 @@
mtu += ETHER_HDR_LEN;
if (if_getcapenable(ifp) & IFCAP_VLAN_MTU)
mtu += ETHER_VLAN_ENCAP_LEN;
- error = DPAA2_CMD_NI_SET_MFL(dev, child, &cmd, mtu);
- if (error) {
+
+ rc = dpaa2_ni_cmd_open(sc, &cmd, &rc_token, &ni_token);
+ if (rc != 0)
+ break;
+ rc = DPAA2_CMD_NI_SET_MFL(dev, dev, &cmd, mtu);
+ if (rc != 0)
device_printf(dev, "%s: failed to update maximum frame "
- "length: error=%d\n", __func__, error);
- goto close_ni;
- }
+ "length: error=%d\n", __func__, rc);
+ dpaa2_ni_cmd_close(sc, &cmd, rc_token, ni_token);
+ break;
+ }
+ case SIOCGI2C:
+ /* SFP+ EEPROM access -- talks to an i2c bus, not the MC. */
+ rc = dpaa2_ni_sfp_ioctl(sc, ifr);
break;
case SIOCSIFCAP:
changed = if_getcapenable(ifp) ^ ifr->ifr_reqcap;
@@ -2682,16 +2811,7 @@
break;
}
- (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
- (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
return (rc);
-
-close_ni:
- (void)DPAA2_CMD_NI_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, ni_token));
-close_rc:
- (void)DPAA2_CMD_RC_CLOSE(dev, child, DPAA2_CMD_TK(&cmd, rc_token));
-err_exit:
- return (error);
}
static int
@@ -3829,6 +3949,7 @@
DRIVER_MODULE(dpaa2_ni, dpaa2_rc, dpaa2_ni_driver, 0, 0);
MODULE_DEPEND(dpaa2_ni, miibus, 1, 1, 1);
+MODULE_DEPEND(dpaa2_ni, sff, 1, 1, 1);
#ifdef DEV_ACPI
MODULE_DEPEND(dpaa2_ni, memac_mdio_acpi, 1, 1, 1);
#endif
Index: sys/dev/sff/sff.h
===================================================================
--- /dev/null
+++ sys/dev/sff/sff.h
@@ -0,0 +1,51 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2026 Xiangbo Kong <yarshure@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _DEV_SFF_SFF_H_
+#define _DEV_SFF_SFF_H_
+
+/*
+ * Read from an SFP module's EEPROM page over i2c.
+ *
+ * dev_addr is the 8-bit (left-aligned) page address, i.e. 0xA0 for the base
+ * SFF-8472 page and 0xA2 for the diagnostics page. The bus is held for the
+ * whole exchange (offset write with a repeat-start, then read).
+ *
+ * When muxaddr != 0 an i2c-mux channel is selected before the read (by writing
+ * chsel to the 7-bit mux address muxaddr) and restored afterwards (chrestore).
+ * This is for platforms whose i2c mux has no driver (e.g. some ACPI systems);
+ * pass muxaddr == 0 when the mux is switched transparently by the i2c
+ * framework, which is the normal FDT case.
+ *
+ * requester must be a device sitting on the target iicbus (e.g. its iic(4)
+ * child); it is used as the bus-request owner.
+ */
+int sff_read_eeprom(device_t requester, int muxaddr, uint8_t chsel,
+ uint8_t chrestore, uint8_t dev_addr, uint8_t offset, uint8_t *buf,
+ int len);
+
+#endif /* _DEV_SFF_SFF_H_ */
Index: sys/dev/sff/sff.c
===================================================================
--- /dev/null
+++ sys/dev/sff/sff.c
@@ -0,0 +1,111 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2026 Xiangbo Kong <yarshure@gmail.com>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * Small Form Factor (SFF) Committee Pluggable (SFP) Transceiver: shared i2c
+ * helpers used by the bus-specific front-ends (sfp_fdt, ...) and by NIC drivers
+ * that must drive an i2c mux themselves.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+
+#include <dev/iicbus/iic.h>
+#include <dev/iicbus/iiconf.h>
+
+#include "sff.h"
+
+int
+sff_read_eeprom(device_t requester, int muxaddr, uint8_t chsel,
+ uint8_t chrestore, uint8_t dev_addr, uint8_t offset, uint8_t *buf, int len)
+{
+ device_t bus = device_get_parent(requester);
+ struct iic_msg sel, rd[2];
+ uint8_t off = offset;
+ int error;
+
+ /*
+ * Hold the bus across the (optional) mux channel select, the offset
+ * write and the data read, so no other consumer can switch the mux or
+ * see it pointed at this device mid-transaction.
+ */
+ error = iicbus_request_bus(bus, requester, IIC_INTRWAIT);
+ if (error != 0)
+ return (iic2errno(error));
+
+ if (muxaddr != 0) {
+ sel.slave = (uint16_t)muxaddr << 1;
+ sel.flags = IIC_M_WR;
+ sel.len = 1;
+ sel.buf = &chsel;
+ error = iicbus_transfer(requester, &sel, 1);
+ }
+
+ if (error == 0) {
+ /* Write the byte offset (repeat-start), then read the data. */
+ rd[0].slave = dev_addr; /* already 8-bit (0xA0/0xA2) */
+ rd[0].flags = IIC_M_WR | IIC_M_NOSTOP;
+ rd[0].len = 1;
+ rd[0].buf = &off;
+ rd[1].slave = dev_addr;
+ rd[1].flags = IIC_M_RD;
+ rd[1].len = len;
+ rd[1].buf = buf;
+ error = iicbus_transfer(requester, rd, 2);
+ }
+
+ if (muxaddr != 0) {
+ sel.slave = (uint16_t)muxaddr << 1;
+ sel.flags = IIC_M_WR;
+ sel.len = 1;
+ sel.buf = &chrestore;
+ (void)iicbus_transfer(requester, &sel, 1);
+ }
+
+ iicbus_release_bus(bus, requester);
+ return (error != 0 ? iic2errno(error) : 0);
+}
+
+static int
+sff_modevent(module_t mod __unused, int type, void *data __unused)
+{
+ switch (type) {
+ case MOD_LOAD:
+ case MOD_UNLOAD:
+ case MOD_QUIESCE:
+ return (0);
+ default:
+ return (EOPNOTSUPP);
+ }
+}
+
+static moduledata_t sff_moduledata = { "sff", sff_modevent, NULL };
+DECLARE_MODULE(sff, sff_moduledata, SI_SUB_DRIVERS, SI_ORDER_ANY);
+MODULE_VERSION(sff, 1);
+MODULE_DEPEND(sff, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
Index: sys/dev/sff/sff_if.m
===================================================================
--- sys/dev/sff/sff_if.m
+++ sys/dev/sff/sff_if.m
@@ -33,3 +33,15 @@
device_t dev;
device_t *i2c_bus;
};
+
+#
+# Read from an SFP module EEPROM page (dev_addr is the 8-bit page address,
+# e.g. 0xA0 base / 0xA2 diagnostics) starting at the given byte offset.
+#
+METHOD int read_eeprom {
+ device_t dev;
+ uint8_t dev_addr;
+ uint8_t offset;
+ uint8_t *buf;
+ int len;
+};
Index: sys/dev/sff/sfp_fdt.c
===================================================================
--- sys/dev/sff/sfp_fdt.c
+++ sys/dev/sff/sfp_fdt.c
@@ -38,6 +38,7 @@
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/fdt/simplebus.h>
+#include "sff.h"
#include "sff_if.h"
struct sfp_fdt_softc {
@@ -134,6 +135,30 @@
return (0);
}
+static int
+sfp_fdt_read_eeprom(device_t dev, uint8_t dev_addr, uint8_t offset,
+ uint8_t *buf, int len)
+{
+ device_t i2c_bus, requester;
+ int error;
+
+ error = sfp_fdt_get_i2c_bus(dev, &i2c_bus);
+ if (error != 0)
+ return (error);
+
+ /*
+ * The "i2c-bus" phandle points at the (possibly muxed) iicbus the
+ * module EEPROM sits on; any i2c mux is switched transparently by the
+ * i2c framework, so we just need a device on that bus to drive the
+ * transfer (no explicit channel select).
+ */
+ requester = device_find_child(i2c_bus, "iic", -1);
+ if (requester == NULL)
+ return (ENXIO);
+
+ return (sff_read_eeprom(requester, 0, 0, 0, dev_addr, offset, buf, len));
+}
+
static device_method_t sfp_fdt_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, sfp_fdt_probe),
@@ -141,6 +166,7 @@
/* SFF */
DEVMETHOD(sff_get_i2c_bus, sfp_fdt_get_i2c_bus),
+ DEVMETHOD(sff_read_eeprom, sfp_fdt_read_eeprom),
DEVMETHOD_END
};
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sat, Oct 3, 11:47 PM (21 h, 42 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
40161213
Default Alt Text
D58258.id186422.diff (19 KB)
Attached To
Mode
D58258: dpaa2: read SFP+ module EEPROM through SIOCGI2C
Attached
Detach File
Event Timeline
Log In to Comment