diff --git a/drivers/net/miidev.c b/drivers/net/miidev.c index d23775b..b49944b 100644 --- a/drivers/net/miidev.c +++ b/drivers/net/miidev.c @@ -123,7 +123,7 @@ int miidev_get_status(struct mii_device *mdev) { - int ret, status; + int ret, status, adv, lpa; ret = mii_read(mdev, mdev->address, MII_BMSR); if (ret < 0) @@ -136,13 +136,31 @@ goto err_out; if (ret & BMCR_ANENABLE) { - ret = mii_read(mdev, mdev->address, MII_LPA); - if (ret < 0) + if (mdev->capabilities & MIIDEV_CAPABLE_1000M) { + lpa = mii_read(mdev, mdev->address, MII_STAT1000); + if (lpa < 0) + goto err_out; + adv = mii_read(mdev, mdev->address, MII_CTRL1000); + if (adv < 0) + goto err_out; + lpa &= adv << 2; + if (lpa & (LPA_1000FULL | LPA_1000HALF)) { + if (lpa & LPA_1000FULL) + status |= MIIDEV_STATUS_IS_FULL_DUPLEX; + status |= MIIDEV_STATUS_IS_1000MBIT; + return status; + } + } + lpa = mii_read(mdev, mdev->address, MII_LPA); + if (lpa < 0) goto err_out; - - status |= ret & LPA_DUPLEX ? MIIDEV_STATUS_IS_FULL_DUPLEX : 0; - status |= ret & LPA_100 ? MIIDEV_STATUS_IS_100MBIT : - MIIDEV_STATUS_IS_10MBIT; + adv = mii_read(mdev, mdev->address, MII_ADVERTISE); + if (adv < 0) + goto err_out; + lpa &= adv; + status |= lpa & LPA_DUPLEX ? MIIDEV_STATUS_IS_FULL_DUPLEX : 0; + status |= lpa & LPA_100 ? MIIDEV_STATUS_IS_100MBIT : + MIIDEV_STATUS_IS_10MBIT; } else { status |= ret & BMCR_FULLDPLX ? MIIDEV_STATUS_IS_FULL_DUPLEX : 0; status |= ret & BMCR_SPEED100 ? MIIDEV_STATUS_IS_100MBIT : @@ -170,8 +188,8 @@ return status; duplex = status & MIIDEV_STATUS_IS_FULL_DUPLEX ? "Full" : "Half"; - speed = status & MIIDEV_STATUS_IS_100MBIT ? 100 : 10; - + speed = status & MIIDEV_STATUS_IS_1000MBIT ? 1000 : + (status & MIIDEV_STATUS_IS_100MBIT ? 100 : 10); printf("%s: Link is %s", mdev->cdev.name, status & MIIDEV_STATUS_IS_UP ? "up" : "down"); @@ -186,11 +204,11 @@ uint16_t *buf = _buf; struct mii_device *mdev = cdev->priv; - while (i > 1) { - *buf = mii_read(mdev, mdev->address, offset); + while (i > 0) { + *buf = mii_read(mdev, mdev->address, offset / 2); buf++; i -= 2; - offset++; + offset += 2; } return count; @@ -202,11 +220,11 @@ const uint16_t *buf = _buf; struct mii_device *mdev = cdev->priv; - while (i > 1) { - mii_write(mdev, mdev->address, offset, *buf); + while (i > 0) { + mii_write(mdev, mdev->address, offset / 2, *buf); buf++; i -= 2; - offset++; + offset += 2; } return count; @@ -221,7 +239,27 @@ static int miidev_probe(struct device_d *dev) { struct mii_device *mdev = dev->priv; + int val; + int caps = 0; + val = mii_read(mdev, mdev->address, MII_PHYSID1); + if (val < 0 || val == 0xffff) + goto err_out; + val = mii_read(mdev, mdev->address, MII_PHYSID2); + if (val < 0 || val == 0xffff) + goto err_out; + val = mii_read(mdev, mdev->address, MII_BMSR); + if (val < 0) + goto err_out; + if (val & BMSR_ESTATEN) { + val = mii_read(mdev, mdev->address, MII_ESTATUS); + if (val < 0) + goto err_out; + if (val & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) + caps = MIIDEV_CAPABLE_1000M; + } + + mdev->capabilities = caps; mdev->cdev.name = asprintf("phy%d", dev->id); mdev->cdev.size = 64; mdev->cdev.ops = &miidev_ops; @@ -230,6 +268,10 @@ devfs_create(&mdev->cdev); list_add_tail(&mdev->list, &miidev_list); return 0; + +err_out: + dev_err(dev, "cannot read PHY registers (addr %d)\n", mdev->address); + return -ENODEV; } static void miidev_remove(struct device_d *dev) diff --git a/include/miidev.h b/include/miidev.h index 622784f..4bbf94c 100644 --- a/include/miidev.h +++ b/include/miidev.h @@ -31,6 +31,8 @@ #define MIIDEV_FORCE_10 (1 << 0) #define MIIDEV_FORCE_LINK (1 << 1) +#define MIIDEV_CAPABLE_1000M (1 << 0) + struct mii_device { struct device_d dev; struct device_d *parent; @@ -40,6 +42,7 @@ int (*write) (struct mii_device *dev, int addr, int reg, int value); int flags; + int capabilities; struct eth_device *edev; struct cdev cdev; @@ -55,6 +58,7 @@ #define MIIDEV_STATUS_IS_FULL_DUPLEX (1 << 1) #define MIIDEV_STATUS_IS_10MBIT (1 << 2) #define MIIDEV_STATUS_IS_100MBIT (1 << 3) +#define MIIDEV_STATUS_IS_1000MBIT (1 << 4) int miidev_print_status(struct mii_device *mdev); static int inline mii_write(struct mii_device *dev, int addr, int reg, int value) diff --git a/include/net.h b/include/net.h index 08f897e..9152943 100644 --- a/include/net.h +++ b/include/net.h @@ -38,8 +38,8 @@ int (*send) (struct eth_device*, void *packet, int length); int (*recv) (struct eth_device*); void (*halt) (struct eth_device*); - int (*get_ethaddr) (struct eth_device*, unsigned char *adr); - int (*set_ethaddr) (struct eth_device*, unsigned char *adr); + int (*get_ethaddr) (struct eth_device*, u8 adr[6]); + int (*set_ethaddr) (struct eth_device*, u8 adr[6]); struct eth_device *next; void *priv; @@ -287,8 +287,8 @@ IPaddr_t getenv_ip(const char *name); int setenv_ip(const char *name, IPaddr_t ip); -int string_to_ethaddr(const char *str, char *enetaddr); -void ethaddr_to_string(const unsigned char *enetaddr, char *str); +int string_to_ethaddr(const char *str, u8 enetaddr[6]); +void ethaddr_to_string(const u8 enetaddr[6], char *str); #ifdef CONFIG_NET_RESOLV IPaddr_t resolv(char *host); diff --git a/net/eth.c b/net/eth.c index e023d65..c034eaa 100644 --- a/net/eth.c +++ b/net/eth.c @@ -167,7 +167,7 @@ static int eth_set_ethaddr(struct device_d *dev, struct param_d *param, const char *val) { struct eth_device *edev = dev_to_edev(dev); - char ethaddr[sizeof("xx:xx:xx:xx:xx:xx")]; + u8 ethaddr[6]; if (!val) return dev_param_set_generic(dev, param, NULL); diff --git a/net/net.c b/net/net.c index c803c48..54d8c25 100644 --- a/net/net.c +++ b/net/net.c @@ -159,7 +159,7 @@ puts(ip_to_string(x)); } -int string_to_ethaddr(const char *str, char *enetaddr) +int string_to_ethaddr(const char *str, u8 enetaddr[6]) { int reg; char *e; @@ -181,7 +181,7 @@ return 0; } -void ethaddr_to_string(const unsigned char *enetaddr, char *str) +void ethaddr_to_string(const u8 enetaddr[6], char *str) { sprintf(str, "%02X:%02X:%02X:%02X:%02X:%02X", enetaddr[0], enetaddr[1], enetaddr[2], enetaddr[3],