freebsd11_network: adapt code based on needs of the rtl81xx R11.1 driver.

This commit is contained in:
Jérôme Duval
2017-11-18 16:34:12 +01:00
parent 1c53604c91
commit 76ad0d68c3
10 changed files with 401 additions and 224 deletions
+10
View File
@@ -522,6 +522,16 @@ bus_child_present(device_t child)
}
void
bus_enumerate_hinted_children(device_t bus)
{
#if 0
UNIMPLEMENTED();
#endif
}
// #pragma mark - PCI functions
@@ -99,6 +99,9 @@ resolve_method(driver_t *driver, const char *name)
method = driver->methods[i].method;
}
if (method == NULL)
panic("resolve_method: method%s not found\n", name);
return method;
}
@@ -304,6 +307,19 @@ device_set_driver(device_t dev, driver_t *driver)
dev->methods.miibus_linkchg = (void *)mth->method;
else if (!strcmp(mth->name, "miibus_mediainit"))
dev->methods.miibus_mediainit = (void *)mth->method;
else if (!strcmp(mth->name, "bus_child_location_str"))
dev->methods.bus_child_location_str = (void *)mth->method;
else if (!strcmp(mth->name, "bus_child_pnpinfo_str"))
dev->methods.bus_child_pnpinfo_str = (void *)mth->method;
else if (!strcmp(mth->name, "bus_hinted_child"))
dev->methods.bus_hinted_child = (void *)mth->method;
else if (!strcmp(mth->name, "bus_print_child"))
dev->methods.bus_print_child = (void *)mth->method;
else if (!strcmp(mth->name, "bus_read_ivar"))
dev->methods.bus_read_ivar = (void *)mth->method;
else
panic("device_set_driver: method %s not found\n", mth->name);
}
return 0;
@@ -1,4 +1,4 @@
/* $NetBSD: mii.h,v 1.9 2001/05/31 03:07:14 thorpej Exp $ */
/* $NetBSD: mii.h,v 1.18 2014/06/16 14:43:22 msaitoh Exp $ */
/*-
* Copyright (c) 1997 Manuel Bouyer. All rights reserved.
@@ -87,7 +87,7 @@
/*
* Note that the EXTSTAT bit indicates that there is extended status
* info available in register 15, but 802.3 section 22.2.4.3 also
* states that that all 1000 Mb/s capable PHYs will set this bit to 1.
* states that all 1000 Mb/s capable PHYs will set this bit to 1.
*/
#define BMSR_MEDIAMASK (BMSR_100T4|BMSR_100TXFDX|BMSR_100TXHDX| \
@@ -111,6 +111,7 @@
#define ANAR_NP 0x8000 /* Next page (ro) */
#define ANAR_ACK 0x4000 /* link partner abilities acknowledged (ro) */
#define ANAR_RF 0x2000 /* remote fault (ro) */
/* Annex 28B.2 */
#define ANAR_FC 0x0400 /* local device supports PAUSE */
#define ANAR_T4 0x0200 /* local device supports 100bT4 */
#define ANAR_TX_FD 0x0100 /* local device supports 100bTx FD */
@@ -123,6 +124,7 @@
#define ANAR_PAUSE_ASYM (2 << 10)
#define ANAR_PAUSE_TOWARDS (3 << 10)
/* Annex 28D */
#define ANAR_X_FD 0x0020 /* local device supports 1000BASE-X FD */
#define ANAR_X_HD 0x0040 /* local device supports 1000BASE-X HD */
#define ANAR_X_PAUSE_NONE (0 << 7)
@@ -184,12 +186,47 @@
#define GTSR_MAN_MS_FLT 0x8000 /* master/slave config fault */
#define GTSR_MS_RES 0x4000 /* result: 1 = master, 0 = slave */
#define GTSR_LRS 0x2000 /* local rx status, 1 = ok */
#define GTSR_RRS 0x1000 /* remove rx status, 1 = ok */
#define GTSR_RRS 0x1000 /* remote rx status, 1 = ok */
#define GTSR_LP_1000TFDX 0x0800 /* link partner 1000baseT FDX capable */
#define GTSR_LP_1000THDX 0x0400 /* link partner 1000baseT HDX capable */
#define GTSR_LP_ASM_DIR 0x0200 /* link partner asym. pause dir. capable */
#define GTSR_IDLE_ERR 0x00ff /* IDLE error count */
#define MII_PSECR 0x0b /* PSE control register */
#define PSECR_PACTLMASK 0x000c /* pair control mask */
#define PSECR_PSEENMASK 0x0003 /* PSE enable mask */
#define PSECR_PINOUTB 0x0008 /* PSE pinout Alternative B */
#define PSECR_PINOUTA 0x0004 /* PSE pinout Alternative A */
#define PSECR_FOPOWTST 0x0002 /* Force Power Test Mode */
#define PSECR_PSEEN 0x0001 /* PSE Enabled */
#define PSECR_PSEDIS 0x0000 /* PSE Disabled */
#define MII_PSESR 0x0c /* PSE status register */
#define PSESR_PWRDENIED 0x1000 /* Power Denied */
#define PSESR_VALSIG 0x0800 /* Valid PD signature detected */
#define PSESR_INVALSIG 0x0400 /* Invalid PD signature detected */
#define PSESR_SHORTCIRC 0x0200 /* Short circuit condition detected */
#define PSESR_OVERLOAD 0x0100 /* Overload condition detected */
#define PSESR_MPSABSENT 0x0080 /* MPS absent condition detected */
#define PSESR_PDCLMASK 0x0070 /* PD Class mask */
#define PSESR_STATMASK 0x000e /* PSE Status mask */
#define PSESR_PAIRCTABL 0x0001 /* PAIR Control Ability */
#define PSESR_PDCL_4 (4 << 4) /* Class 4 */
#define PSESR_PDCL_3 (3 << 4) /* Class 3 */
#define PSESR_PDCL_2 (2 << 4) /* Class 2 */
#define PSESR_PDCL_1 (1 << 4) /* Class 1 */
#define PSESR_PDCL_0 (0 << 4) /* Class 0 */
#define MII_MMDACR 0x0d /* MMD access control register */
#define MMDACR_FUNCMASK 0xc000 /* function */
#define MMDACR_DADDRMASK 0x001f /* device address */
#define MMDACR_FN_ADDRESS (0 << 14) /* address */
#define MMDACR_FN_DATANPI (1 << 14) /* data, no post increment */
#define MMDACR_FN_DATAPIRW (2 << 14) /* data, post increment on r/w */
#define MMDACR_FN_DATAPIW (3 << 14) /* data, post increment on wr only */
#define MII_MMDAADR 0x0e /* MMD access address data register */
#define MII_EXTSR 0x0f /* Extended status register */
#define EXTSR_1000XFDX 0x8000 /* 1000X full-duplex capable */
#define EXTSR_1000XHDX 0x4000 /* 1000X half-duplex capable */
@@ -53,7 +53,7 @@ oui BROADCOM 0x001018 Broadcom Corporation
oui BROADCOM2 0x000af7 Broadcom Corporation
oui BROADCOM3 0x001be9 Broadcom Corporation
oui BROADCOM4 0x18c086 Broadcom Corporation
oui CICADA 0x0003F1 Cicada Semiconductor
oui CICADA 0x0003f1 Cicada Semiconductor
oui DAVICOM 0x00606e Davicom Semiconductor
oui ENABLESEMI 0x0010dd Enable Semiconductor
oui ICPLUS 0x0090c3 IC Plus Corp.
@@ -62,6 +62,7 @@ oui INTEL 0x00aa00 Intel Corporation
oui JMICRON 0x00d831 JMicron Technologies
oui LEVEL1 0x00207b Level 1
oui MARVELL 0x005043 Marvell Semiconductor
oui MICREL 0x0010a1 Micrel
oui MYSON 0x00c0b4 Myson Technology
oui NATSEMI 0x080017 National Semiconductor
oui PMCSIERRA 0x00e004 PMC-Sierra
@@ -70,8 +71,10 @@ oui RDC 0x00d02d RDC Semiconductor
oui REALTEK 0x00e04c RealTek Semicondctor
oui SEEQ 0x00a07d Seeq Technology
oui SIS 0x00e006 Silicon Integrated Systems
oui SMC 0x00800f SMC
oui TI 0x080028 Texas Instruments
oui TSC 0x00c039 TDK Semiconductor
oui VITESSE 0x0001c1 Vitesse Semiconductor
oui XAQTI 0x00e0ae XaQti Corp.
/* Some Intel 82553's use an alternative OUI. */
@@ -134,6 +137,7 @@ model yyAMD 79c901home 0x0039 Am79C901 HomePNA 1.0 interface
/* Atheros Communications/Attansic PHYs */
model xxATHEROS F1 0x0001 Atheros F1 10/100/1000 PHY
model xxATHEROS F2 0x0002 Atheros F2 10/100 PHY
model xxATHEROS AR8021 0x0004 Atheros AR8021 10/100/1000 PHY
model xxATHEROS F1_7 0x0007 Atheros F1 10/100/1000 PHY
/* Asix semiconductor PHYs */
@@ -150,7 +154,10 @@ model xxBROADCOM BCM4401 0x0036 BCM4401 10/100 media interface
model xxBROADCOM BCM5365 0x0037 BCM5365 10/100 5-port PHY switch
model BROADCOM BCM5400 0x0004 BCM5400 1000BASE-T media interface
model BROADCOM BCM5401 0x0005 BCM5401 1000BASE-T media interface
model BROADCOM BCM5402 0x0006 BCM5402 1000BASE-T media interface
model BROADCOM BCM5411 0x0007 BCM5411 1000BASE-T media interface
model BROADCOM BCM5404 0x0008 BCM5404 1000BASE-T media interface
model BROADCOM BCM5424 0x000a BCM5424/BCM5234 1000BASE-T media interface
model BROADCOM BCM5464 0x000b BCM5464 1000BASE-T media interface
model BROADCOM BCM5461 0x000c BCM5461 1000BASE-T media interface
model BROADCOM BCM5462 0x000d BCM5462 1000BASE-T media interface
@@ -166,12 +173,15 @@ model BROADCOM BCM54K2 0x002e BCM54K2 1000BASE-T media interface
model BROADCOM BCM5714 0x0034 BCM5714 1000BASE-T media interface
model BROADCOM BCM5780 0x0035 BCM5780 1000BASE-T media interface
model BROADCOM BCM5708C 0x0036 BCM5708C 1000BASE-T media interface
model BROADCOM BCM5466 0x003b BCM5466 1000BASE-T media interface
model BROADCOM2 BCM5325 0x0003 BCM5325 10/100 5-port PHY switch
model BROADCOM2 BCM5906 0x0004 BCM5906 10/100baseTX media interface
model BROADCOM2 BCM5478 0x0008 BCM5478 1000BASE-T media interface
model BROADCOM2 BCM5488 0x0009 BCM5488 1000BASE-T media interface
model BROADCOM2 BCM5481 0x000a BCM5481 1000BASE-T media interface
model BROADCOM2 BCM5482 0x000b BCM5482 1000BASE-T media interface
model BROADCOM2 BCM5755 0x000c BCM5755 1000BASE-T media interface
model BROADCOM2 BCM5754 0x000e BCM5754/5787 1000BASE-T media interface
model BROADCOM2 BCM5754 0x000e BCM5754/BCM5787 1000BASE-T media interface
model BROADCOM2 BCM5708S 0x0015 BCM5708S 1000/2500baseSX PHY
model BROADCOM2 BCM5785 0x0016 BCM5785 1000BASE-T media interface
model BROADCOM2 BCM5709CAX 0x002c BCM5709CAX 10/100/1000baseT PHY
@@ -192,6 +202,7 @@ model xxBROADCOM_ALT1 BCM5906 0x0004 BCM5906 10/100baseTX media interface
model xxCICADA CS8201 0x0001 Cicada CS8201 10/100/1000TX PHY
model xxCICADA CS8204 0x0004 Cicada CS8204 10/100/1000TX PHY
model xxCICADA VSC8211 0x000b Cicada VSC8211 10/100/1000TX PHY
model xxCICADA VSC8221 0x0015 Cicada CS8201 10/100/1000TX PHY
model xxCICADA CS8201A 0x0020 Cicada CS8201 10/100/1000TX PHY
model xxCICADA CS8201B 0x0021 Cicada CS8201 10/100/1000TX PHY
model xxCICADA CS8244 0x002c Cicada CS8244 10/100/1000TX PHY
@@ -270,6 +281,10 @@ model MARVELL E1000_3 0x0003 Marvell 88E1000 Gigabit PHY
model MARVELL E1000_5 0x0005 Marvell 88E1000 Gigabit PHY
model MARVELL E1111 0x000c Marvell 88E1111 Gigabit PHY
/* Micrel PHYs */
model MICREL KSZ9021 0x0021 Micrel KSZ9021 10/100/1000 PHY
model MICREL KSZ9031 0x0022 Micrel KSZ9031 10/100/1000 PHY
/* Myson Technology PHYs */
model xxMYSON MTD972 0x0000 MTD972 10/100 media interface
model MYSON MTD803 0x0000 MTD803 3-in-1 media interface
@@ -321,5 +336,12 @@ model TI TNETE2101 0x0003 TNETE2101 media interface
model xxTSC 78Q2120 0x0014 78Q2120 10/100 media interface
model xxTSC 78Q2121 0x0015 78Q2121 100BASE-TX media interface
/* Vitesse Semiconductor */
model xxVITESSE VSC8641 0x0003 Vitesse VSC8641 10/100/1000TX PHY
/* XaQti Corp. PHYs */
model xxXAQTI XMACII 0x0000 XaQti Corp. XMAC II gigabit interface
/* SMC */
model SMC LAN8710A 0x000F SMC LAN8710A 10/100 interface
model SMC LAN8700 0x000C SMC LAN8700 10/100 interface
@@ -36,6 +36,7 @@
#define _DEV_MII_MIIVAR_H_
#include <sys/queue.h>
#include <net/if_var.h> /* XXX driver API temporary */
/*
* Media Independent Interface data structure defintions
@@ -43,13 +44,6 @@
struct mii_softc;
/*
* Callbacks from MII layer into network interface device driver.
*/
typedef int (*mii_readreg_t)(struct device *, int, int);
typedef void (*mii_writereg_t)(struct device *, int, int, int);
typedef void (*mii_statchg_t)(struct device *);
/*
* A network interface driver has one of these structures in its softc.
* It is the interface from the network interface driver to the MII
@@ -57,7 +51,7 @@ typedef void (*mii_statchg_t)(struct device *);
*/
struct mii_data {
struct ifmedia mii_media; /* media information */
struct ifnet *mii_ifp; /* pointer back to network interface */
if_t mii_ifp; /* pointer back to network interface */
/*
* For network interfaces with multiple PHYs, a list of all
@@ -72,13 +66,6 @@ struct mii_data {
*/
u_int mii_media_status;
u_int mii_media_active;
/*
* Calls from MII layer into network interface driver.
*/
mii_readreg_t mii_readreg;
mii_writereg_t mii_writereg;
mii_statchg_t mii_statchg;
};
typedef struct mii_data mii_data_t;
@@ -193,27 +180,6 @@ struct mii_phydesc {
MII_STR_ ## a ## _ ## b }
#define MII_PHY_END { 0, 0, NULL }
/*
* An array of these structures map MII media types to BMCR/ANAR settings.
*/
struct mii_media {
u_int mm_bmcr; /* BMCR settings for this media */
u_int mm_anar; /* ANAR settings for this media */
u_int mm_gtcr; /* 100base-T2 or 1000base-T CR */
};
#define MII_MEDIA_NONE 0
#define MII_MEDIA_10_T 1
#define MII_MEDIA_10_T_FDX 2
#define MII_MEDIA_100_T4 3
#define MII_MEDIA_100_TX 4
#define MII_MEDIA_100_TX_FDX 5
#define MII_MEDIA_1000_X 6
#define MII_MEDIA_1000_X_FDX 7
#define MII_MEDIA_1000_T 8
#define MII_MEDIA_1000_T_FDX 9
#define MII_NMEDIA 10
#ifdef _KERNEL
#ifdef __HAIKU__
@@ -270,30 +236,24 @@ MIIBUS_ACCESSOR(flags, FLAGS, u_int)
extern devclass_t miibus_devclass;
extern driver_t miibus_driver;
int miibus_probe(device_t);
int miibus_attach(device_t);
int miibus_detach(device_t);
int mii_attach(device_t, device_t *, struct ifnet *, ifm_change_cb_t,
int mii_attach(device_t, device_t *, if_t, ifm_change_cb_t,
ifm_stat_cb_t, int, int, int, int);
void mii_down(struct mii_data *);
int mii_mediachg(struct mii_data *);
void mii_tick(struct mii_data *);
void mii_pollstat(struct mii_data *);
void mii_phy_add_media(struct mii_softc *);
#ifdef __HAIKU__
int mii_media_from_bmcr(int);
#endif
int mii_phy_auto(struct mii_softc *);
int mii_phy_detach(device_t dev);
void mii_phy_down(struct mii_softc *);
u_int mii_phy_flowstatus(struct mii_softc *);
void mii_phy_reset(struct mii_softc *);
void mii_phy_setmedia(struct mii_softc *sc);
void mii_phy_update(struct mii_softc *, int);
int mii_phy_tick(struct mii_softc *);
int mii_phy_mac_match(struct mii_softc *, const char *);
int mii_dev_mac_match(device_t, const char *);
void *mii_phy_mac_softc(struct mii_softc *);
void *mii_dev_mac_softc(device_t);
const struct mii_phydesc * mii_phy_match(const struct mii_attach_args *ma,
const struct mii_phydesc *mpd);
@@ -95,6 +95,7 @@ void bus_release_resources(device_t dev,
const struct resource_spec *resourceSpec, struct resource **resources);
int bus_child_present(device_t child);
void bus_enumerate_hinted_children(device_t bus);
static inline struct resource *
bus_alloc_resource_any(device_t dev, int type, int *rid, uint32 flags)
@@ -13,6 +13,8 @@
#include <kernel/lock.h>
#include <net_stack.h>
#undef __unused
#define __unused
#undef ASSERT
/* private/kernel/debug.h sets it */
@@ -28,6 +30,21 @@ typedef int device_detach_t(device_t dev);
typedef int device_resume_t(device_t dev);
typedef int device_suspend_t(device_t dev);
typedef int bus_child_location_str_t(device_t dev __unused, device_t child,
char *buf, size_t buflen);
typedef int bus_child_pnpinfo_str_t(device_t dev __unused, device_t child,
char *buf, size_t buflen);
typedef void bus_hinted_child_t(device_t dev, const char *name, int unit);
typedef int bus_print_child_t(device_t dev, device_t child);
typedef int bus_read_ivar_t(device_t dev, device_t child __unused, int which,
uintptr_t *result);
typedef int miibus_readreg_t(device_t dev, int phy, int reg);
typedef int miibus_writereg_t(device_t dev, int phy, int reg, int data);
typedef void miibus_statchg_t(device_t dev);
typedef void miibus_linkchg_t(device_t dev);
typedef void miibus_mediainit_t(device_t dev);
struct device_method {
const char *name;
device_method_signature_t method;
+156 -63
View File
@@ -53,8 +53,8 @@ __FBSDID("$FreeBSD$");
#include <sys/bus.h>
#include <net/if.h>
#include <net/if_var.h>
#include <net/if_media.h>
#include <net/route.h>
#include <dev/mii/mii.h>
#include <dev/mii/miivar.h>
@@ -63,18 +63,20 @@ MODULE_VERSION(miibus, 1);
#include "miibus_if.h"
static int miibus_print_child(device_t dev, device_t child);
static int miibus_read_ivar(device_t dev, device_t child, int which,
uintptr_t *result);
static int miibus_child_location_str(device_t bus, device_t child, char *buf,
size_t buflen);
static int miibus_child_pnpinfo_str(device_t bus, device_t child, char *buf,
size_t buflen);
static int miibus_readreg(device_t, int, int);
static int miibus_writereg(device_t, int, int, int);
static void miibus_statchg(device_t);
static void miibus_linkchg(device_t);
static void miibus_mediainit(device_t);
static device_attach_t miibus_attach;
static bus_child_location_str_t miibus_child_location_str;
static bus_child_pnpinfo_str_t miibus_child_pnpinfo_str;
static device_detach_t miibus_detach;
static bus_hinted_child_t miibus_hinted_child;
static bus_print_child_t miibus_print_child;
static device_probe_t miibus_probe;
static bus_read_ivar_t miibus_read_ivar;
static miibus_readreg_t miibus_readreg;
static miibus_statchg_t miibus_statchg;
static miibus_writereg_t miibus_writereg;
static miibus_linkchg_t miibus_linkchg;
static miibus_mediainit_t miibus_mediainit;
static unsigned char mii_bitreverse(unsigned char x);
static device_method_t miibus_methods[] = {
@@ -87,9 +89,9 @@ static device_method_t miibus_methods[] = {
/* bus interface */
DEVMETHOD(bus_print_child, miibus_print_child),
DEVMETHOD(bus_read_ivar, miibus_read_ivar),
DEVMETHOD(bus_driver_added, bus_generic_driver_added),
DEVMETHOD(bus_child_pnpinfo_str, miibus_child_pnpinfo_str),
DEVMETHOD(bus_child_location_str, miibus_child_location_str),
DEVMETHOD(bus_hinted_child, miibus_hinted_child),
/* MII interface */
DEVMETHOD(miibus_readreg, miibus_readreg),
@@ -98,7 +100,7 @@ static device_method_t miibus_methods[] = {
DEVMETHOD(miibus_linkchg, miibus_linkchg),
DEVMETHOD(miibus_mediainit, miibus_mediainit),
{ 0, 0 }
DEVMETHOD_END
};
devclass_t miibus_devclass;
@@ -110,13 +112,14 @@ driver_t miibus_driver = {
};
struct miibus_ivars {
struct ifnet *ifp;
if_t ifp;
ifm_change_cb_t ifmedia_upd;
ifm_stat_cb_t ifmedia_sts;
int mii_flags;
u_int mii_flags;
u_int mii_offset;
};
int
static int
miibus_probe(device_t dev)
{
@@ -125,7 +128,7 @@ miibus_probe(device_t dev)
return (BUS_PROBE_SPECIFIC);
}
int
static int
miibus_attach(device_t dev)
{
struct miibus_ivars *ivars;
@@ -135,7 +138,6 @@ miibus_attach(device_t dev)
int i, nchildren;
mii = device_get_softc(dev);
nchildren = 0;
if (device_get_children(dev, &children, &nchildren) == 0) {
for (i = 0; i < nchildren; i++) {
ma = device_get_ivars(children[i]);
@@ -151,14 +153,14 @@ miibus_attach(device_t dev)
ifmedia_init(&mii->mii_media, IFM_IMASK, ivars->ifmedia_upd,
ivars->ifmedia_sts);
mii->mii_ifp = ivars->ifp;
mii->mii_ifp->if_capabilities |= IFCAP_LINKSTATE;
mii->mii_ifp->if_capenable |= IFCAP_LINKSTATE;
if_setcapabilitiesbit(mii->mii_ifp, IFCAP_LINKSTATE, 0);
if_setcapenablebit(mii->mii_ifp, IFCAP_LINKSTATE, 0);
LIST_INIT(&mii->mii_phys);
return (bus_generic_attach(dev));
}
int
static int
miibus_detach(device_t dev)
{
struct mii_data *mii;
@@ -207,7 +209,7 @@ miibus_read_ivar(device_t dev, device_t child __unused, int which,
}
static int
miibus_child_pnpinfo_str(device_t bus __unused, device_t child, char *buf,
miibus_child_pnpinfo_str(device_t dev __unused, device_t child, char *buf,
size_t buflen)
{
struct mii_attach_args *ma;
@@ -220,7 +222,7 @@ miibus_child_pnpinfo_str(device_t bus __unused, device_t child, char *buf,
}
static int
miibus_child_location_str(device_t bus __unused, device_t child, char *buf,
miibus_child_location_str(device_t dev __unused, device_t child, char *buf,
size_t buflen)
{
struct mii_attach_args *ma;
@@ -230,6 +232,60 @@ miibus_child_location_str(device_t bus __unused, device_t child, char *buf,
return (0);
}
static void
miibus_hinted_child(device_t dev, const char *name, int unit)
{
struct miibus_ivars *ivars;
struct mii_attach_args *args, *ma;
device_t *children, phy;
int i, nchildren;
u_int val;
if (resource_int_value(name, unit, "phyno", &val) != 0)
return;
if (device_get_children(dev, &children, &nchildren) != 0)
return;
ma = NULL;
for (i = 0; i < nchildren; i++) {
args = device_get_ivars(children[i]);
if (args->mii_phyno == val) {
ma = args;
break;
}
}
free(children, M_TEMP);
/*
* Don't add a PHY that was automatically identified by having media
* in its BMSR twice, only allow to alter its attach arguments.
*/
if (ma == NULL) {
ma = malloc(sizeof(struct mii_attach_args), M_DEVBUF,
M_NOWAIT);
if (ma == NULL)
return;
phy = device_add_child(dev, name, unit);
if (phy == NULL) {
free(ma, M_DEVBUF);
return;
}
ivars = device_get_ivars(dev);
ma->mii_phyno = val;
ma->mii_offset = ivars->mii_offset++;
ma->mii_id1 = 0;
ma->mii_id2 = 0;
ma->mii_capmask = BMSR_DEFCAPMASK;
device_set_ivars(phy, ma);
}
if (resource_int_value(name, unit, "id1", &val) == 0)
ma->mii_id1 = val;
if (resource_int_value(name, unit, "id2", &val) == 0)
ma->mii_id2 = val;
if (resource_int_value(name, unit, "capmask", &val) == 0)
ma->mii_capmask = val;
}
static int
miibus_readreg(device_t dev, int phy, int reg)
{
@@ -258,7 +314,7 @@ miibus_statchg(device_t dev)
MIIBUS_STATCHG(parent);
mii = device_get_softc(dev);
mii->mii_ifp->if_baudrate = ifmedia_baudrate(mii->mii_media_active);
if_setbaudrate(mii->mii_ifp, ifmedia_baudrate(mii->mii_media_active));
}
static void
@@ -308,14 +364,15 @@ miibus_mediainit(device_t dev)
* the PHYs to the network interface driver parent.
*/
int
mii_attach(device_t dev, device_t *miibus, struct ifnet *ifp,
mii_attach(device_t dev, device_t *miibus, if_t ifp,
ifm_change_cb_t ifmedia_upd, ifm_stat_cb_t ifmedia_sts, int capmask,
int phyloc, int offloc, int flags)
{
struct miibus_ivars *ivars;
struct mii_attach_args ma, *args;
struct mii_attach_args *args, ma;
device_t *children, phy;
int bmsr, first, i, nchildren, offset, phymax, phymin, rv;
int bmsr, first, i, nchildren, phymax, phymin, rv;
uint32_t phymask;
if (phyloc != MII_PHY_ANY && offloc != MII_OFFSET_ANY) {
printf("%s: phyloc and offloc specified\n", __func__);
@@ -323,7 +380,7 @@ mii_attach(device_t dev, device_t *miibus, struct ifnet *ifp,
}
if (offloc != MII_OFFSET_ANY && (offloc < 0 || offloc >= MII_NPHY)) {
printf("%s: ivalid offloc %d\n", __func__, offloc);
printf("%s: invalid offloc %d\n", __func__, offloc);
return (EINVAL);
}
@@ -332,7 +389,7 @@ mii_attach(device_t dev, device_t *miibus, struct ifnet *ifp,
phymax = MII_NPHY - 1;
} else {
if (phyloc < 0 || phyloc >= MII_NPHY) {
printf("%s: ivalid phyloc %d\n", __func__, phyloc);
printf("%s: invalid phyloc %d\n", __func__, phyloc);
return (EINVAL);
}
phymin = phymax = phyloc;
@@ -372,27 +429,30 @@ mii_attach(device_t dev, device_t *miibus, struct ifnet *ifp,
ma.mii_capmask = capmask;
phy = NULL;
offset = 0;
if (resource_int_value(device_get_name(*miibus),
device_get_unit(*miibus), "phymask", &phymask) != 0)
phymask = 0xffffffff;
if (device_get_children(*miibus, &children, &nchildren) != 0) {
children = NULL;
nchildren = 0;
}
ivars->mii_offset = 0;
for (ma.mii_phyno = phymin; ma.mii_phyno <= phymax; ma.mii_phyno++) {
/*
* Make sure we haven't already configured a PHY at this
* address. This allows mii_attach() to be called
* multiple times.
*/
if (device_get_children(*miibus, &children, &nchildren) == 0) {
for (i = 0; i < nchildren; i++) {
args = device_get_ivars(children[i]);
if (args->mii_phyno == ma.mii_phyno) {
/*
* Yes, there is already something
* configured at this address.
*/
free(children, M_TEMP);
goto skip;
}
for (i = 0; i < nchildren; i++) {
args = device_get_ivars(children[i]);
if (args->mii_phyno == ma.mii_phyno) {
/*
* Yes, there is already something
* configured at this address.
*/
goto skip;
}
free(children, M_TEMP);
}
/*
@@ -411,18 +471,24 @@ mii_attach(device_t dev, device_t *miibus, struct ifnet *ifp,
* There is a PHY at this address. If we were given an
* `offset' locator, skip this PHY if it doesn't match.
*/
if (offloc != MII_OFFSET_ANY && offloc != offset)
if (offloc != MII_OFFSET_ANY && offloc != ivars->mii_offset)
goto skip;
/*
* Extract the IDs. Braindead PHYs will be handled by
* Skip this PHY if it's not included in the phymask hint.
*/
if ((phymask & (1 << ma.mii_phyno)) == 0)
goto skip;
/*
* Extract the IDs. Braindead PHYs will be handled by
* the `ukphy' driver, as we have no ID information to
* match on.
*/
ma.mii_id1 = MIIBUS_READREG(dev, ma.mii_phyno, MII_PHYIDR1);
ma.mii_id2 = MIIBUS_READREG(dev, ma.mii_phyno, MII_PHYIDR2);
ma.mii_offset = offset;
ma.mii_offset = ivars->mii_offset;
args = malloc(sizeof(struct mii_attach_args), M_DEVBUF,
M_NOWAIT);
if (args == NULL)
@@ -435,11 +501,20 @@ mii_attach(device_t dev, device_t *miibus, struct ifnet *ifp,
}
device_set_ivars(phy, args);
skip:
offset++;
ivars->mii_offset++;
}
free(children, M_TEMP);
if (first != 0) {
if (phy == NULL) {
rv = device_set_driver(*miibus, &miibus_driver);
if (rv != 0)
goto fail;
bus_enumerate_hinted_children(*miibus);
rv = device_get_children(*miibus, &children, &nchildren);
if (rv != 0)
goto fail;
free(children, M_TEMP);
if (nchildren == 0) {
rv = ENXIO;
goto fail;
}
@@ -543,22 +618,10 @@ mii_pollstat(struct mii_data *mii)
}
}
/*
* Inform the PHYs that the interface is down.
*/
void
mii_down(struct mii_data *mii)
{
struct mii_softc *child;
LIST_FOREACH(child, &mii->mii_phys, mii_list)
mii_phy_down(child);
}
static unsigned char
mii_bitreverse(unsigned char x)
{
unsigned const char const nibbletab[16] = {
static unsigned const char nibbletab[16] = {
0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15
};
@@ -576,3 +639,33 @@ mii_oui(u_int id1, u_int id2)
(mii_bitreverse((h >> 8) & 0xff) << 8) |
mii_bitreverse(h & 0xff));
}
int
mii_phy_mac_match(struct mii_softc *mii, const char *name)
{
return (strcmp(device_get_name(device_get_parent(mii->mii_dev)),
name) == 0);
}
int
mii_dev_mac_match(device_t parent, const char *name)
{
return (strcmp(device_get_name(device_get_parent(
device_get_parent(parent))), name) == 0);
}
void *
mii_phy_mac_softc(struct mii_softc *mii)
{
return (device_get_softc(device_get_parent(mii->mii_dev)));
}
void *
mii_dev_mac_softc(device_t parent)
{
return (device_get_softc(device_get_parent(device_get_parent(parent))));
}
@@ -31,7 +31,7 @@
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/sys/dev/mii/mii_physubr.c,v 1.22.2.2 2006/07/29 08:30:12 oleg Exp $");
__FBSDID("$FreeBSD$");
/*
* Subroutines common to all PHYs.
@@ -54,9 +54,28 @@ __FBSDID("$FreeBSD: src/sys/dev/mii/mii_physubr.c,v 1.22.2.2 2006/07/29 08:30:12
#include "miibus_if.h"
/*
* Media to register setting conversion table. Order matters.
*
* An array of structures to map MII media types to BMCR/ANAR settings.
*/
static const struct mii_media mii_media_table[MII_NMEDIA] = {
enum {
MII_MEDIA_NONE = 0,
MII_MEDIA_10_T,
MII_MEDIA_10_T_FDX,
MII_MEDIA_100_T4,
MII_MEDIA_100_TX,
MII_MEDIA_100_TX_FDX,
MII_MEDIA_1000_X,
MII_MEDIA_1000_X_FDX,
MII_MEDIA_1000_T,
MII_MEDIA_1000_T_FDX,
MII_NMEDIA,
};
static const struct mii_media {
u_int mm_bmcr; /* BMCR settings for this media */
u_int mm_anar; /* ANAR settings for this media */
u_int mm_gtcr; /* 100base-T2 or 1000base-T CR */
} mii_media_table[MII_NMEDIA] = {
/* None */
{ BMCR_ISO, ANAR_CSMA,
0, },
@@ -104,8 +123,10 @@ mii_phy_setmedia(struct mii_softc *sc)
struct mii_data *mii = sc->mii_pdata;
struct ifmedia_entry *ife = mii->mii_media.ifm_cur;
int bmcr, anar, gtcr;
int index = -1;
if (IFM_SUBTYPE(ife->ifm_media) == IFM_AUTO) {
switch (IFM_SUBTYPE(ife->ifm_media)) {
case IFM_AUTO:
/*
* Force renegotiation if MIIF_DOPAUSE or MIIF_FORCEANEG.
* The former is necessary as we might switch from flow-
@@ -115,19 +136,78 @@ mii_phy_setmedia(struct mii_softc *sc)
(sc->mii_flags & (MIIF_DOPAUSE | MIIF_FORCEANEG)) != 0)
(void)mii_phy_auto(sc);
return;
case IFM_NONE:
index = MII_MEDIA_NONE;
break;
case IFM_HPNA_1:
index = MII_MEDIA_10_T;
break;
case IFM_10_T:
switch (IFM_OPTIONS(ife->ifm_media)) {
case 0:
index = MII_MEDIA_10_T;
break;
case IFM_FDX:
case (IFM_FDX | IFM_FLOW):
index = MII_MEDIA_10_T_FDX;
break;
}
break;
case IFM_100_TX:
case IFM_100_FX:
switch (IFM_OPTIONS(ife->ifm_media)) {
case 0:
index = MII_MEDIA_100_TX;
break;
case IFM_FDX:
case (IFM_FDX | IFM_FLOW):
index = MII_MEDIA_100_TX_FDX;
break;
}
break;
case IFM_100_T4:
index = MII_MEDIA_100_T4;
break;
case IFM_1000_SX:
switch (IFM_OPTIONS(ife->ifm_media)) {
case 0:
index = MII_MEDIA_1000_X;
break;
case IFM_FDX:
case (IFM_FDX | IFM_FLOW):
index = MII_MEDIA_1000_X_FDX;
break;
}
break;
case IFM_1000_T:
switch (IFM_OPTIONS(ife->ifm_media)) {
case 0:
case IFM_ETH_MASTER:
index = MII_MEDIA_1000_T;
break;
case IFM_FDX:
case (IFM_FDX | IFM_ETH_MASTER):
case (IFM_FDX | IFM_FLOW):
case (IFM_FDX | IFM_FLOW | IFM_ETH_MASTER):
index = MII_MEDIA_1000_T_FDX;
break;
}
break;
}
/*
* Table index is stored in the media entry.
*/
KASSERT(index != -1, ("%s: failed to map media word %d",
__func__, ife->ifm_media));
KASSERT(ife->ifm_data >=0 && ife->ifm_data < MII_NMEDIA,
("invalid ife->ifm_data (0x%x) in mii_phy_setmedia",
ife->ifm_data));
anar = mii_media_table[ife->ifm_data].mm_anar;
bmcr = mii_media_table[ife->ifm_data].mm_bmcr;
gtcr = mii_media_table[ife->ifm_data].mm_gtcr;
anar = mii_media_table[index].mm_anar;
bmcr = mii_media_table[index].mm_bmcr;
gtcr = mii_media_table[index].mm_gtcr;
if (IFM_SUBTYPE(ife->ifm_media) == IFM_1000_T) {
gtcr |= GTCR_MAN_MS;
@@ -209,13 +289,8 @@ int
mii_phy_tick(struct mii_softc *sc)
{
struct ifmedia_entry *ife = sc->mii_pdata->mii_media.ifm_cur;
struct ifnet *ifp = sc->mii_pdata->mii_ifp;
int reg;
/* Just bail now if the interface is down. */
if ((ifp->if_flags & IFF_UP) == 0)
return (EJUSTRETURN);
/*
* If we're not doing autonegotiation, we don't need to do
* any extra work here. However, we need to check the link
@@ -283,12 +358,6 @@ mii_phy_reset(struct mii_softc *sc)
PHY_WRITE(sc, MII_BMCR, reg);
}
void
mii_phy_down(struct mii_softc *sc)
{
}
void
mii_phy_update(struct mii_softc *sc, int cmd)
{
@@ -305,56 +374,6 @@ mii_phy_update(struct mii_softc *sc, int cmd)
}
}
/*
* Given an ifmedia word, return the corresponding ANAR value.
*/
int
mii_anar(int media)
{
int rv;
switch (media & (IFM_TMASK|IFM_NMASK|IFM_FDX)) {
case IFM_ETHER|IFM_10_T:
rv = ANAR_10|ANAR_CSMA;
break;
case IFM_ETHER|IFM_10_T|IFM_FDX:
rv = ANAR_10_FD|ANAR_CSMA;
break;
case IFM_ETHER|IFM_100_TX:
rv = ANAR_TX|ANAR_CSMA;
break;
case IFM_ETHER|IFM_100_TX|IFM_FDX:
rv = ANAR_TX_FD|ANAR_CSMA;
break;
case IFM_ETHER|IFM_100_T4:
rv = ANAR_T4|ANAR_CSMA;
break;
default:
rv = 0;
break;
}
return (rv);
}
/*
* Given a BMCR value, return the corresponding ifmedia word.
*/
int
mii_media_from_bmcr(int bmcr)
{
int rv = IFM_ETHER;
if (bmcr & BMCR_S100)
rv |= IFM_100_TX;
else
rv |= IFM_10_T;
if (bmcr & BMCR_FDX)
rv |= IFM_FDX;
return (rv);
}
/*
* Initialize generic PHY media based on BMSR, called when a PHY is
* attached. We expect to be set up to print a comma-separated list
@@ -367,18 +386,23 @@ mii_phy_add_media(struct mii_softc *sc)
const char *sep = "";
int fdx = 0;
if ((sc->mii_capabilities & BMSR_MEDIAMASK) == 0 &&
(sc->mii_extcapabilities & EXTSR_MEDIAMASK) == 0) {
printf("no media present");
return;
}
/*
* Set the autonegotiation timer for 10/100 media. Gigabit media is
* handled below.
*/
sc->mii_anegticks = MII_ANEGTICKS;
#define ADD(m, c) ifmedia_add(&mii->mii_media, (m), (c), NULL)
#define ADD(m) ifmedia_add(&mii->mii_media, (m), 0, NULL)
#define PRINT(s) printf("%s%s", sep, s); sep = ", "
if ((sc->mii_flags & MIIF_NOISOLATE) == 0) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst),
MII_MEDIA_NONE);
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_NONE, 0, sc->mii_inst));
PRINT("none");
}
@@ -390,51 +414,44 @@ mii_phy_add_media(struct mii_softc *sc)
if ((sc->mii_flags & MIIF_IS_HPNA) != 0) {
if ((sc->mii_capabilities & BMSR_10THDX) != 0) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_HPNA_1, 0,
sc->mii_inst), MII_MEDIA_10_T);
sc->mii_inst));
PRINT("HomePNA1");
}
return;
}
if ((sc->mii_capabilities & BMSR_10THDX) != 0) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst),
MII_MEDIA_10_T);
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, 0, sc->mii_inst));
PRINT("10baseT");
}
if ((sc->mii_capabilities & BMSR_10TFDX) != 0) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst),
MII_MEDIA_10_T_FDX);
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T, IFM_FDX, sc->mii_inst));
PRINT("10baseT-FDX");
if ((sc->mii_flags & MIIF_DOPAUSE) != 0 &&
(sc->mii_flags & MIIF_NOMANPAUSE) == 0) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_10_T,
IFM_FDX | IFM_FLOW, sc->mii_inst),
MII_MEDIA_10_T_FDX);
IFM_FDX | IFM_FLOW, sc->mii_inst));
PRINT("10baseT-FDX-flow");
}
fdx = 1;
}
if ((sc->mii_capabilities & BMSR_100TXHDX) != 0) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst),
MII_MEDIA_100_TX);
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, 0, sc->mii_inst));
PRINT("100baseTX");
}
if ((sc->mii_capabilities & BMSR_100TXFDX) != 0) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst),
MII_MEDIA_100_TX_FDX);
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX, IFM_FDX, sc->mii_inst));
PRINT("100baseTX-FDX");
if ((sc->mii_flags & MIIF_DOPAUSE) != 0 &&
(sc->mii_flags & MIIF_NOMANPAUSE) == 0) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_TX,
IFM_FDX | IFM_FLOW, sc->mii_inst),
MII_MEDIA_100_TX_FDX);
IFM_FDX | IFM_FLOW, sc->mii_inst));
PRINT("100baseTX-FDX-flow");
}
fdx = 1;
}
if ((sc->mii_capabilities & BMSR_100T4) != 0) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst),
MII_MEDIA_100_T4);
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_100_T4, 0, sc->mii_inst));
PRINT("100baseT4");
}
@@ -447,20 +464,19 @@ mii_phy_add_media(struct mii_softc *sc)
sc->mii_anegticks = MII_ANEGTICKS_GIGE;
sc->mii_flags |= MIIF_IS_1000X;
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, 0,
sc->mii_inst), MII_MEDIA_1000_X);
sc->mii_inst));
PRINT("1000baseSX");
}
if ((sc->mii_extcapabilities & EXTSR_1000XFDX) != 0) {
sc->mii_anegticks = MII_ANEGTICKS_GIGE;
sc->mii_flags |= MIIF_IS_1000X;
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX, IFM_FDX,
sc->mii_inst), MII_MEDIA_1000_X_FDX);
sc->mii_inst));
PRINT("1000baseSX-FDX");
if ((sc->mii_flags & MIIF_DOPAUSE) != 0 &&
(sc->mii_flags & MIIF_NOMANPAUSE) == 0) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_SX,
IFM_FDX | IFM_FLOW, sc->mii_inst),
MII_MEDIA_1000_X_FDX);
IFM_FDX | IFM_FLOW, sc->mii_inst));
PRINT("1000baseSX-FDX-flow");
}
fdx = 1;
@@ -476,31 +492,29 @@ mii_phy_add_media(struct mii_softc *sc)
sc->mii_anegticks = MII_ANEGTICKS_GIGE;
sc->mii_flags |= MIIF_HAVE_GTCR;
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, 0,
sc->mii_inst), MII_MEDIA_1000_T);
sc->mii_inst));
PRINT("1000baseT");
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T,
IFM_ETH_MASTER, sc->mii_inst), MII_MEDIA_1000_T);
IFM_ETH_MASTER, sc->mii_inst));
PRINT("1000baseT-master");
}
if ((sc->mii_extcapabilities & EXTSR_1000TFDX) != 0) {
sc->mii_anegticks = MII_ANEGTICKS_GIGE;
sc->mii_flags |= MIIF_HAVE_GTCR;
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T, IFM_FDX,
sc->mii_inst), MII_MEDIA_1000_T_FDX);
sc->mii_inst));
PRINT("1000baseT-FDX");
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T,
IFM_FDX | IFM_ETH_MASTER, sc->mii_inst),
MII_MEDIA_1000_T_FDX);
IFM_FDX | IFM_ETH_MASTER, sc->mii_inst));
PRINT("1000baseT-FDX-master");
if ((sc->mii_flags & MIIF_DOPAUSE) != 0 &&
(sc->mii_flags & MIIF_NOMANPAUSE) == 0) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T,
IFM_FDX | IFM_FLOW, sc->mii_inst),
MII_MEDIA_1000_T_FDX);
IFM_FDX | IFM_FLOW, sc->mii_inst));
PRINT("1000baseT-FDX-flow");
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_1000_T,
IFM_FDX | IFM_FLOW | IFM_ETH_MASTER,
sc->mii_inst), MII_MEDIA_1000_T_FDX);
sc->mii_inst));
PRINT("1000baseT-FDX-flow-master");
}
fdx = 1;
@@ -509,12 +523,11 @@ mii_phy_add_media(struct mii_softc *sc)
if ((sc->mii_capabilities & BMSR_ANEG) != 0) {
/* intentionally invalid index */
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst),
MII_NMEDIA);
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, 0, sc->mii_inst));
PRINT("auto");
if (fdx != 0 && (sc->mii_flags & MIIF_DOPAUSE) != 0) {
ADD(IFM_MAKEWORD(IFM_ETHER, IFM_AUTO, IFM_FLOW,
sc->mii_inst), MII_NMEDIA);
sc->mii_inst));
PRINT("auto-flow");
}
}
@@ -528,7 +541,6 @@ mii_phy_detach(device_t dev)
struct mii_softc *sc;
sc = device_get_softc(dev);
mii_phy_down(sc);
sc->mii_dev = NULL;
LIST_REMOVE(sc, mii_list);
return (0);
@@ -43,6 +43,15 @@ struct device {
void (*miibus_statchg)(device_t);
void (*miibus_linkchg)(device_t);
void (*miibus_mediainit)(device_t);
int (*bus_child_location_str)(device_t dev __unused, device_t child,
char *buf, size_t buflen);
int (*bus_child_pnpinfo_str)(device_t dev __unused, device_t child,
char *buf, size_t buflen);
void (*bus_hinted_child)(device_t dev, const char *name, int unit);
int (*bus_print_child)(device_t dev, device_t child);
int (*bus_read_ivar)(device_t dev, device_t child __unused, int which,
uintptr_t *result);
} methods;
struct list_link link;