Page MenuHomeFreeBSD

D58258.id186422.diff
No OneTemporary

D58258.id186422.diff

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

Mime Type
text/plain
Expires
Sun, Oct 4, 2:00 PM (21 h, 15 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
40161213
Default Alt Text
D58258.id186422.diff (19 KB)

Event Timeline