Subject: MII & GMII Common Layer [PSARC/2009/319 FastTrack timeout 06/01/2009] To: PSARC-ext@Sun.Com Cc: brussels-dev@sun.com, sstallion@gmail.com Bcc: one-pager-list@sac.sfbay one-pager-log@sac.sfbay sac-bar@sac.sfbay I'm sponsoring this on my own behalf. I think it qualifies for a fast track, but it might be pushing the limits. I won't be offended if a member decides otherwise and derails. :-) (Just don't expect *me* to derail it. :-) And to answer any questions: Yes, I do have a working prototype of this available. Check out http://cr.opensolaris.org/~gdamore/mii/ for code. Template Version: @(#)sac_nextcase 1.68 02/23/09 SMI This information is Copyright 2009 Sun Microsystems 1. Introduction 1.1. Project/Component Working Name: MII & GMII Common Layer 1.2. Name of Document Author/Supplier: Author: Garrett D'Amore 1.3 Date of This Document: 22 May, 2009 4. Technical Description MII & GMII proposal =================== Author: Garrett D'Amore Date: Fri May 22, 2009 FastTrack: MII & GMII Common Layer Release Binding: Minor OVERVIEW -------- We propose to provide a replacement for the legacy x86 only mii module that supports both SPARC and x86, and supports the various 10, 100, and 1000 base MII and GMII registers (see 802.3-2008 clauses 22, 28, and 37). 10G interfaces use a different management interface, which can support some of these same registers, but which is different in non-trivial ways, and therefore we do not intend at this time to support 10G interfaces. The new module should be able to support the existing MII consumers with modest change, plus all of the current 10/100/1000 drivers which support MII or GMII access to transceivers. Additionally, we want to have flexibility to support the various vendor specific hacks that are necessary with many transceivers. Support is also present (but untested) for 100Base-T2, 100Base-T4, and 1000Base-X links. The MII module will fully support Brussels (PSARC 2007/429) and GLDv3 statistics routines, but this support will only be available for GLDv3 based drivers. The MII module also supports PHY internal and external loopback modes, and the netlbtest SunVTS test, thus greatly expanding upon the set of devices supported by this test. COMMITMENT & BINDING -------------------- All of the interfaces detailed in this proposal are intended (at least initially) to be Consolidation Private. Once GLDv3 is given a public commitment, and once we have some more experience with these interfaces, it will probably be appropriate to raise their commitment level. We're seeking Minor binding at the moment, as we have concrete plans to backport this. We do believe that at some point in the future it may be useful to have this in an earlier release to facilitate backporting of certain other MAC drivers, but some significant modication will need to be made to replace the generic Brussels interfaces with interfaces more appropriate for Solaris 10 (i.e. ndd support.) (Unless Brussels itself is backported.) Hence, we feel that if a backport is desired, another case should be opened to address the issues associated with such. COMPATIBILITY ------------- As indicated, the new MII module should be able to support any reasonable MII consumers. However, some legacy consumers use semi-private legacy interface for MII. These drivers will need some small attention to make them work -- they are dnet, elxl, and iprb. I've already converted iprb (which gains a lot of new functionality as a result) and elxl (which does not, because it is still a GLDv2 driver). Fixing dnet might be more work than it is worth, in which case the legacy mii.c file and supporting headers will just be moved into a private dnet directory (and suitably renamed of course!) so that it can continue to operate with no risk. Note that drivers that are GLDv3 can benefit the most, but it is not strictly required that drivers be GLDv3 to use the MII module. (Although some of the APIs, such as those for aiding implementation of the mc_setprop and mc_getprop entry points, will be uselss in a driver that is not GLDv3 based.) We'll be breaking support for a few ancient hacks (which we think are no longer needed -- workarounds for errata for specific problems that we believe are no longer relevant), and some of the "device-specific" legacy properties for setting link parameters. (The drivers will now be able to use the uniform dladm interface to manage link settings.) API --- 1. Compilation Drivers access the new API by #include (and optionally also .) The driver will need to depend upon misc/mii using the LDFLAGS of -dy -Nmisc/mii 2. Entry Points. Drivers shall supply the following entry points: struct mii_ops { int mii_version; uint16_t mii_read(); void mii_write(); void mii_notify(); void mii_reset }; int mii_version; This should be assigned to the value MII_VERSION. It is intended to allow for future extensions to the ops structure. (When the structure grows, the version number will be incremented. More detail about how this will be accomplished will be specified when such extensions are necessary.) uint16_t mii_read(void *state, uint8_t phy_addr, uint8_t reg_num); Reads a register, and stores the 16-bit register value in valuep. Returns the value on success, or 0xffff on failure. Note that the register and phy addresses are constrained to values 0-31 per IEEE 802.3 clause 22. The state value is an opaque pointer to the mac driver's soft state. void mii_write(void *state, uint8_t phy_addr, uint8_t reg_num, uint16_t value); Writes the 16-bit value to the named phy and register. Returns 0 on success, or an errno on failure. void mii_notify(void *state, link_state_t state); When the MII module detects a change in the link state on the active PHY, it will call the link notification routine, which will allow the mac driver to do any required reprogramming. Note that the mac driver should call mac_link_update() as appropriate. 3. Functions For Drivers typedef struct mii_handle mii_handle_t; Opaque to drivers, a simple handle to reference the MII state. mii_handle_t *mii_alloc(void *private, dev_info_t*dip, mii_ops_t *ops); Allocate an MII handle. Called during driver's attach(9e) handling, this routine is valid in kernel context only. The "private" argument points to a driver private state structure, which will be passed back to the driver as the first argument to each of its entry points supplied in the ops entry point. The dip is the dev_info node for the MAC instance structure. On success a valid MII handle is returned, otherwise NULL may be returned. void mii_free(mii_handle_t *mii); Free an MII handle and associated resources. Call from detach(9e) handling, this routine is valid in kernel context only. void mii_set_instance(mii_handle_t *mii, uint_t instance); Sets the instance (PPA) of the MAC associated with the MII. Optional, but if called, must be done after mii_alloc(), and before the first time mii_start() is called. If not called, a default instance using ddi_get_instance() from the dev_info node was supplied to mii_alloc will be used. (This function is only needed for drivers that override the value of m_instance in the mac_register structure.) void mii_set_pauseable(mii_handle_t *mii, boolean_t cap, boolean_t asym); Lets the MII know if the MAC layer can support pause or asymetric pause capabilities. The MII layer will use this to determine what capabilities should be negotiated for (along with user preferences, of course.) If not called, the MII will assume the device has no support for flow control. void mii_start(mii_handle_t *mii); Starts monitoring of the MII bus. Normally this is called as a result of a driver's mac_start() entry point, but it may also be called when a PHY needs to be reset or during handling of DDI_RESUME. This function may be called in any context except high level interrupt, but must be called without any locks held. void mii_stop(mii_handle_t *mii); Stops monitoring of the MII bus. Normally this is called as a result of a driver's mac_stop() entry point, but may also be called during DDI_SUSPEND handling. As a side effect, also isolates and powers down any active PHY. On return, the MII layer is guaranteed not to be executing any code in the MII entry points. This function may be called in any context except high level interrupt, but must be called without any locks held. void mii_probe(mii_handle_t *mii); Used to reset the entire MII bus and probe for PHYs. This routine should be called if the driver has reason to believe that PHYs have changed. This is implicitly executed the first time monitoring is started on the MII bus, and normally need not be explicitly called. This function may only be called in any context except high level interrupt, but must be called without any locks held. void mii_check(mii_handle_t *mii); Used to alert the MII layer that it should check for changes. This can be called by drivers in response to link status interrupts, for example, giving a quicker response to link status changes without waiting for the MII timer to expire. This function may be called in any context except high level interrupt, but must be called without any locks held. int mii_get_addr(mii_handle_t *mii); Used to get the PHY address that is currently active for the MII bus. This function may be called in any context. The returned address will be a number 0 to 31 if a PHY is present and in use, or -1 otherwise. uint32_t mii_get_id(mii_handle_t *mii); Used to get the identifier of the active PHY. This function may be called in any context. The PHY identifier register contents, encoded with the high order (PHYIDH) bits in the upper word and the low order bits in the lower word are returned. If no PHY is active, the value -1 will be returned. Note that it is perfectly reasonable for a PHY to have no ID registers, in which case a value of either 0 or (uint32_t)-1 may be returned. int mii_get_speed(mii_handle_t *mii); Used to get the speed of the active PHY. This function may be called in any context. The returned value is the speed, in Mbps, if the active PHY has link (10, 100, or 1000), otherwise 0. link_duplex_t mii_get_duplex(mii_handle_t *mii); Used to get the duplex of the active PHY. This function may be called in any context. The returned value will be the duplex, if the active PHY has link (LINK_DUPLEX_FULL or LINK_DUPLEX_HALF), otherwise LINK_DUPLEX_UNKNOWN. link_state_t mii_get_state(mii_handle_t *mii); Used to get the state of the link on the active PHY. This function may be called in any context. The returned value indicates the link state, one of LINK_STATE_UP, LINK_STATE_DOWN, or LINK_STATE_UNKNOWN. link_flowctrl_t mii_get_flowctrl(mii_handle_t *mii); Used to get the state of the negotiated flow control on the active PHY. This function may be called in any context. Note that the name of returned value indicates the direction of the pause frame, not the direction of the flow. Hence, LINK_FLOWCTRL_RX indicates that the local station may receive pause frames (which ultimately should cause it to defer transmission), and LINK_FLOWCTRL_TX indicates that the local station may send pause frames when it is unable to process any further received packets. LINK_FLOWCTRL_BI indicates that pause frames may be sent either from or to the station, and LINK_FLOWCTRL_NONE means that no pause frames should be sent or handled specially. int mii_get_loopmodes(mii_handle_t *mii, lb_property_t *modes); #define MII_LOOPBACK_MAX 16 #define MII_LOOPBACK_NONE 0 This function is used to support the LB_GET_INFO_SIZE and LB_GET_INFO ioctls. It probably should not be used outside of that context. The modes supplied are supported by the MII/PHY. Drivers may wish to add modes for MAC internal loopbacks as well. See for more information. Note that the first item in the modes array will always be the mode to disable the MII/PHY loopback, and will have the value MII_LOOPBACK_NONE. The modes pointer may be NULL, to retrieve just the count of the number modes that would be returned, otherwise it must point to a location with enough room to hold all the modes. The return value indicates the number of loopback modes returned, which will in no case be more than MII_LOOPBACK_MAX. (Hence, drivers may use a scratch array with MII_LOOPBACK_MAX lb_property_t's in it without concern about overrunning the array.) int mii_set_loopback(mii_handle_t *mii, uint32_t mode); Sets the loopback mode, intended for use in support of the LB_SET_MODE ioctl. The mode value will be one of the values returned in the modes array (see mii_get_loopmodes), or the special value MII_LOOPBACK_NONE to return to normal operation. Returns zero on succes, or EINVAL if the requested mode is invalid or unsupported. uint32_t mii_get_loopback(mii_handle_t *mii); Queries the current loopback mode, intended for use in support of the LB_GET_MODE ioctl, but may be useful in programming device settings that are sensitive to loopback setting. boolean_t mii_m_loop_ioctl(mii_handle_t *mii, queue_t *wq, mblk_t *msg); Used to support the driver's mc_ioctl() for loopback ioctls. If the driver is going to use the loopback optons from the PHY, and isn't adding any MAC level loopback, then this function can handle the entire set of ioctls, further simplifying the MAC driver. Ultimately, this is a very reasonable thing to do, since the PHY level loopback should exercise all of the same MAC level circuitry that a MAC internal loopback would do. (Hence there should be little need to add support for a MAC level loopback.) The wq and msg are passed directly from the mc_ioctl entry point. Returns B_TRUE if the MII layer recognized and processed the ioctl, or B_FALSE otherwise. If B_TRUE is returned, the driver can simply terminate ioctl processing. If B_FALSE is returned, the driver will need to process and ack or nak the ioctl. int mii_m_getprop(mii_handle_t *mii, const char *name, mac_prop_id_t id, uint_t flags, uint_t sz, void *val, uint_t *perm); Used to support the driver's mc_getprop() mac callback, and only to be called from that function (and without any locks held). This routine will process all of the properties that are relevant to MII on behalf of the driver. The arguments (except for the mii handle) are exactly as for the GLDv3 mc_getprop() entry point. On success, it returns 0. If ENOTSUP is returned, the property wasn't one recognized by the MII, and the MAC driver can either process it or return ENOTSUP back to the GLDv3. If any other error is encountered, EINVAL is returned. int mii_m_setprop(mii_handle_t *mii, const char *name, mac_prop_id_t id, uint_t sz, const void *val); Used to support the driver's mc_setprop() mac callback, and only to be called from that function (and without any locks held). This routine will process all of the properties that are relevant to MII on behalf of the driver. This will often result in the PHY being reset. On success, it returns 0. If ENOTSUP is returned, the property wasn't one recognized by the MII, and the MAC driver can either process it or return ENOTSUP back to the GLDv3. If any other error is encountered, EINVAL is returned. int mii_m_getstat(mii_handle_t *mii, uint_t stat, uint64_t *val); Used to support the driver's mc_getstat() mac callback for statistic collection, and only to be called from that function (without any locks held). This routine will process all of the statistics that are relevant to MII on behalf of the driver. Returns 0 if the statistic was processed, or ENOTSUP if the MII does not recognize the statistic. 4. Functions for Phy Specific Overrides Some PHYs require vendor specific tweaks or adjustments. Rather than run separate drivers with different PHYs for each type, we are going to simply compile all the overrides into one binary. All of the interfaces between the vendor specific PHY modules and the MII core are hence Project Private and not covered here. (However, see the private miipriv.h header if interested in the details.) 6. Resources and Schedule 6.4. Steering Committee requested information 6.4.1. Consolidation C-team Name: ON 6.5. ARC review type: FastTrack 6.6. ARC Exposure: open