mirror of
https://github.com/Fishwaldo/build.git
synced 2025-03-27 17:21:34 +00:00
- ax88179 usb3 driver - enabled zram / zcache - enabled IR autorepeat - enabled RC core driver - spdif fixes
2597 lines
71 KiB
Diff
2597 lines
71 KiB
Diff
ax88179_178a USB 3.0 Ethernet
|
|
|
|
|
|
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
|
|
index 1c4aee4..fdcd0bb 100644
|
|
--- a/drivers/net/usb/Kconfig
|
|
+++ b/drivers/net/usb/Kconfig
|
|
@@ -157,6 +157,24 @@ config USB_NET_AX8817X
|
|
This driver creates an interface named "ethX", where X depends on
|
|
what other networking devices you have in use.
|
|
|
|
+config USB_NET_AX88179_178A
|
|
+ tristate "ASIX AX88179/178A USB 3.0/2.0 to Gigabit Ethernet"
|
|
+ depends on USB_USBNET
|
|
+ select CRC32
|
|
+# select PHYLIB
|
|
+ default y
|
|
+ help
|
|
+ This option adds support for ASIX AX88179 based USB 3.0/2.0
|
|
+ to Gigabit Ethernet adapters.
|
|
+
|
|
+ This driver should work with at least the following devices:
|
|
+ * ASIX AX88179
|
|
+ * ASIX AX88178A
|
|
+ * Sitcomm LN-032
|
|
+
|
|
+ This driver creates an interface named "ethX", where X depends on
|
|
+ what other networking devices you have in use.
|
|
+
|
|
config USB_NET_QF9700
|
|
tristate "QF9700 Based USB 2.0 Ethernet Adapters"
|
|
depends on USB_USBNET
|
|
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
|
|
index e307868..6f9dd39 100644
|
|
--- a/drivers/net/usb/Makefile
|
|
+++ b/drivers/net/usb/Makefile
|
|
@@ -8,6 +8,7 @@ obj-$(CONFIG_USB_PEGASUS) += pegasus.o
|
|
obj-$(CONFIG_USB_RTL8150) += rtl8150.o
|
|
obj-$(CONFIG_USB_HSO) += hso.o
|
|
obj-$(CONFIG_USB_NET_AX8817X) += asix.o
|
|
+obj-$(CONFIG_USB_NET_AX88179_178A) += ax88179_178a.o
|
|
obj-$(CONFIG_USB_NET_QF9700) += qf9700.o
|
|
obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o
|
|
obj-$(CONFIG_USB_NET_CDC_EEM) += cdc_eem.o
|
|
diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c
|
|
new file mode 100644
|
|
index 0000000..1c1a14f
|
|
--- /dev/null
|
|
+++ b/drivers/net/usb/ax88179_178a.c
|
|
@@ -0,0 +1,2173 @@
|
|
+/*
|
|
+ * ASIX AX88179 based USB 3.0 Ethernet Devices
|
|
+ * Copyright (C) 2003-2005 David Hollis <dhollis@davehollis.com>
|
|
+ * Copyright (C) 2005 Phil Chang <pchang23@sbcglobal.net>
|
|
+ * Copyright (c) 2002-2003 TiVo Inc.
|
|
+ *
|
|
+ * This program is free software; you can redistribute it and/or modify
|
|
+ * it under the terms of the GNU General Public License as published by
|
|
+ * the Free Software Foundation; either version 2 of the License, or
|
|
+ * (at your option) any later version.
|
|
+ *
|
|
+ * This program is distributed in the hope that it will be useful,
|
|
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ * GNU General Public License for more details.
|
|
+ *
|
|
+ * You should have received a copy of the GNU General Public License
|
|
+ * along with this program; if not, write to the Free Software
|
|
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
+ */
|
|
+
|
|
+/* debug messages, extra info */
|
|
+/* #define DEBUG */
|
|
+
|
|
+#include <linux/version.h>
|
|
+/*#include <linux/config.h>*/
|
|
+#ifdef CONFIG_USB_DEBUG
|
|
+#define DEBUG
|
|
+#endif
|
|
+#include <linux/module.h>
|
|
+#include <linux/kmod.h>
|
|
+#include <linux/sched.h>
|
|
+#include <linux/init.h>
|
|
+#include <linux/netdevice.h>
|
|
+#include <linux/etherdevice.h>
|
|
+#include <linux/ethtool.h>
|
|
+#include <linux/workqueue.h>
|
|
+#include <linux/mii.h>
|
|
+#include <linux/usb.h>
|
|
+#include <linux/crc32.h>
|
|
+#include <linux/if_vlan.h>
|
|
+
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 25)
|
|
+#include <linux/usb/usbnet.h>
|
|
+#else
|
|
+#include <../drivers/usb/net/usbnet.h>
|
|
+#endif
|
|
+
|
|
+#include "ax88179_178a.h"
|
|
+
|
|
+#define DRV_VERSION "1.14.2"
|
|
+
|
|
+static char version[] =
|
|
+KERN_INFO "ASIX USB Ethernet Adapter:v" DRV_VERSION
|
|
+// " " __TIME__ " " __DATE__ "\n"
|
|
+" http://www.asix.com.tw\n";
|
|
+
|
|
+static int msg_enable;
|
|
+module_param(msg_enable, int, 0);
|
|
+MODULE_PARM_DESC(msg_enable, "usbnet msg_enable");
|
|
+
|
|
+static int bsize = -1;
|
|
+module_param(bsize, int, 0);
|
|
+MODULE_PARM_DESC(bsize, "RX Bulk IN Queue Size");
|
|
+
|
|
+static int ifg = -1;
|
|
+module_param(ifg, int, 0);
|
|
+MODULE_PARM_DESC(ifg, "RX Bulk IN Inter Frame Gap");
|
|
+
|
|
+
|
|
+/* EEE advertisement is disabled in default setting */
|
|
+static int bEEE = 0;
|
|
+module_param(bEEE, int, 0);
|
|
+MODULE_PARM_DESC(bEEE, "EEE advertisement configuration");
|
|
+
|
|
+/* Green ethernet advertisement is disabled in default setting */
|
|
+static int bGETH = 0;
|
|
+module_param(bGETH, int, 0);
|
|
+MODULE_PARM_DESC(bGETH, "Green ethernet configuration");
|
|
+/* ASIX AX88179/178A based USB 3.0/2.0 Gigabit Ethernet Devices */
|
|
+
|
|
+static int __ax88179_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
|
|
+ u16 size, void *data, int in_pm)
|
|
+{
|
|
+ int ret;
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
|
|
+ int (*fn)(struct usbnet *, u8, u8, u16, u16, void *, u16);
|
|
+
|
|
+ BUG_ON(!dev);
|
|
+
|
|
+ if (!in_pm)
|
|
+ fn = usbnet_read_cmd;
|
|
+ else
|
|
+ fn = usbnet_read_cmd_nopm;
|
|
+
|
|
+ ret = fn(dev, cmd, USB_DIR_IN | USB_TYPE_VENDOR |
|
|
+ USB_RECIP_DEVICE, value, index, data, size);
|
|
+
|
|
+ if (unlikely(ret < 0))
|
|
+ netdev_warn(dev->net, "Failed to read reg index 0x%04x: %d\n",
|
|
+ index, ret);
|
|
+#else
|
|
+ ret = usb_control_msg(
|
|
+ dev->udev,
|
|
+ usb_rcvctrlpipe(dev->udev, 0),
|
|
+ cmd,
|
|
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
|
+ value,
|
|
+ index,
|
|
+ data,
|
|
+ size,
|
|
+ USB_CTRL_GET_TIMEOUT);
|
|
+#endif
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int __ax88179_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
|
|
+ u16 size, void *data, int in_pm)
|
|
+{
|
|
+ int ret;
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0)
|
|
+ int (*fn)(struct usbnet *, u8, u8, u16, u16, const void *, u16);
|
|
+
|
|
+ BUG_ON(!dev);
|
|
+
|
|
+ if (!in_pm)
|
|
+ fn = usbnet_write_cmd;
|
|
+ else
|
|
+ fn = usbnet_write_cmd_nopm;
|
|
+
|
|
+ ret = fn(dev, cmd, USB_DIR_OUT | USB_TYPE_VENDOR |
|
|
+ USB_RECIP_DEVICE, value, index, data, size);
|
|
+
|
|
+ if (unlikely(ret < 0))
|
|
+ netdev_warn(dev->net, "Failed to write reg index 0x%04x: %d\n",
|
|
+ index, ret);
|
|
+#else
|
|
+ ret = usb_control_msg(
|
|
+ dev->udev,
|
|
+ usb_sndctrlpipe(dev->udev, 0),
|
|
+ cmd,
|
|
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
|
|
+ value,
|
|
+ index,
|
|
+ data,
|
|
+ size,
|
|
+ USB_CTRL_SET_TIMEOUT);
|
|
+
|
|
+#endif
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int ax88179_read_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value,
|
|
+ u16 index, u16 size, void *data, int eflag)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ if (eflag && (2 == size)) {
|
|
+ u16 buf = 0;
|
|
+ ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 1);
|
|
+ le16_to_cpus(&buf);
|
|
+ *((u16 *)data) = buf;
|
|
+ } else if (eflag && (4 == size)) {
|
|
+ u32 buf = 0;
|
|
+ ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 1);
|
|
+ le32_to_cpus(&buf);
|
|
+ *((u32 *)data) = buf;
|
|
+ } else {
|
|
+ ret = __ax88179_read_cmd(dev, cmd, value, index, size, data, 1);
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int ax88179_write_cmd_nopm(struct usbnet *dev, u8 cmd, u16 value,
|
|
+ u16 index, u16 size, void *data)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ if (2 == size) {
|
|
+ u16 buf = 0;
|
|
+ buf = *((u16 *)data);
|
|
+ cpu_to_le16s(&buf);
|
|
+ ret = __ax88179_write_cmd(dev, cmd, value, index,
|
|
+ size, &buf, 1);
|
|
+ } else {
|
|
+ ret = __ax88179_write_cmd(dev, cmd, value, index,
|
|
+ size, data, 1);
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int ax88179_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
|
|
+ u16 size, void *data, int eflag)
|
|
+{
|
|
+
|
|
+ int ret;
|
|
+
|
|
+ if (eflag && (2 == size)) {
|
|
+ u16 buf = 0;
|
|
+ ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 0);
|
|
+ le16_to_cpus(&buf);
|
|
+ *((u16 *)data) = buf;
|
|
+ } else if (eflag && (4 == size)) {
|
|
+ u32 buf = 0;
|
|
+ ret = __ax88179_read_cmd(dev, cmd, value, index, size, &buf, 0);
|
|
+ le32_to_cpus(&buf);
|
|
+ *((u32 *)data) = buf;
|
|
+ } else {
|
|
+ ret = __ax88179_read_cmd(dev, cmd, value, index, size, data, 0);
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int ax88179_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
|
|
+ u16 size, void *data)
|
|
+{
|
|
+ int ret;
|
|
+
|
|
+ if (2 == size) {
|
|
+ u16 buf = 0;
|
|
+ buf = *((u16 *)data);
|
|
+ cpu_to_le16s(&buf);
|
|
+ ret = __ax88179_write_cmd(dev, cmd, value, index,
|
|
+ size, &buf, 0);
|
|
+ } else {
|
|
+ ret = __ax88179_write_cmd(dev, cmd, value, index,
|
|
+ size, data, 0);
|
|
+ }
|
|
+
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 20)
|
|
+static void ax88179_async_cmd_callback(struct urb *urb, struct pt_regs *regs)
|
|
+#else
|
|
+static void ax88179_async_cmd_callback(struct urb *urb)
|
|
+#endif
|
|
+{
|
|
+ struct ax88179_async_handle *asyncdata = (struct ax88179_async_handle *)urb->context;
|
|
+
|
|
+ if (urb->status < 0)
|
|
+ printk(KERN_ERR "ax88179_async_cmd_callback() failed with %d",
|
|
+ urb->status);
|
|
+
|
|
+ kfree(asyncdata->req);
|
|
+ kfree(asyncdata);
|
|
+ usb_free_urb(urb);
|
|
+
|
|
+}
|
|
+
|
|
+static void
|
|
+ax88179_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
|
|
+ u16 size, void *data)
|
|
+{
|
|
+ struct usb_ctrlrequest *req = NULL;
|
|
+ int status = 0;
|
|
+ struct urb *urb = NULL;
|
|
+ void *buf = NULL;
|
|
+ struct ax88179_async_handle *asyncdata = NULL;
|
|
+
|
|
+ urb = usb_alloc_urb(0, GFP_ATOMIC);
|
|
+ if (urb == NULL) {
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
|
|
+ netdev_err(dev->net, "Error allocating URB in write_cmd_async!");
|
|
+#else
|
|
+ deverr(dev, "Error allocating URB in write_cmd_async!");
|
|
+#endif
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ req = kmalloc(sizeof(struct usb_ctrlrequest), GFP_ATOMIC);
|
|
+ if (req == NULL) {
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
|
|
+ netdev_err(dev->net, "Failed to allocate memory for control request");
|
|
+#else
|
|
+ deverr(dev, "Failed to allocate memory for control request");
|
|
+#endif
|
|
+ usb_free_urb(urb);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ asyncdata = (struct ax88179_async_handle*)
|
|
+ kmalloc(sizeof(struct ax88179_async_handle), GFP_ATOMIC);
|
|
+ if (asyncdata == NULL) {
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
|
|
+ netdev_err(dev->net, "Failed to allocate memory for async data");
|
|
+#else
|
|
+ deverr(dev, "Failed to allocate memory for async data");
|
|
+#endif
|
|
+ kfree(req);
|
|
+ usb_free_urb(urb);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ asyncdata->req = req;
|
|
+
|
|
+ if (size == 2) {
|
|
+ asyncdata->rxctl = *((u16 *)data);
|
|
+ cpu_to_le16s(&asyncdata->rxctl);
|
|
+ buf = &asyncdata->rxctl;
|
|
+ } else {
|
|
+ memcpy(asyncdata->m_filter, data, size);
|
|
+ buf = asyncdata->m_filter;
|
|
+ }
|
|
+
|
|
+ req->bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE;
|
|
+ req->bRequest = cmd;
|
|
+ req->wValue = cpu_to_le16(value);
|
|
+ req->wIndex = cpu_to_le16(index);
|
|
+ req->wLength = cpu_to_le16(size);
|
|
+
|
|
+ usb_fill_control_urb(urb, dev->udev,
|
|
+ usb_sndctrlpipe(dev->udev, 0),
|
|
+ (void *)req, buf, size,
|
|
+ ax88179_async_cmd_callback, asyncdata);
|
|
+
|
|
+ status = usb_submit_urb(urb, GFP_ATOMIC);
|
|
+ if (status < 0) {
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
|
|
+ netdev_err(dev->net, "Error submitting the control message: status=%d",
|
|
+ status);
|
|
+#else
|
|
+ deverr(dev, "Error submitting the control message: status=%d",
|
|
+ status);
|
|
+#endif
|
|
+ kfree(req);
|
|
+ kfree(asyncdata);
|
|
+ usb_free_urb(urb);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void ax88179_status(struct usbnet *dev, struct urb *urb)
|
|
+{
|
|
+ struct ax88179_int_data *event = NULL;
|
|
+ int link = 0;
|
|
+
|
|
+ if (urb->actual_length < 8)
|
|
+ return;
|
|
+
|
|
+ event = urb->transfer_buffer;
|
|
+ link = event->link & AX_INT_PPLS_LINK;
|
|
+
|
|
+ if (netif_carrier_ok(dev->net) != link) {
|
|
+ if (link) {
|
|
+ netif_carrier_on(dev->net);
|
|
+ usbnet_defer_kevent(dev, EVENT_LINK_RESET);
|
|
+ }
|
|
+ else
|
|
+ netif_carrier_off(dev->net);
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
|
|
+ netdev_info(dev->net, "ax88179_178a - Link status is: %d\n",
|
|
+ link);
|
|
+#else
|
|
+ devinfo(dev, "ax88179_178a - Link status is: %d\n", link);
|
|
+#endif
|
|
+ }
|
|
+}
|
|
+
|
|
+static int ax88179_mdio_read(struct net_device *netdev, int phy_id, int loc)
|
|
+{
|
|
+ struct usbnet *dev = netdev_priv(netdev);
|
|
+ u16 res = 0;
|
|
+
|
|
+ ax88179_read_cmd(dev, AX_ACCESS_PHY, phy_id, (__u16)loc, 2, &res, 1);
|
|
+ return res;
|
|
+}
|
|
+
|
|
+static void ax88179_mdio_write(struct net_device *netdev, int phy_id, int loc,
|
|
+ int val)
|
|
+{
|
|
+ struct usbnet *dev = netdev_priv(netdev);
|
|
+ u16 res = (u16)val;
|
|
+
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, phy_id, (__u16)loc, 2, &res);
|
|
+}
|
|
+
|
|
+static int ax88179_suspend(struct usb_interface *intf,
|
|
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 10)
|
|
+ pm_message_t message)
|
|
+#else
|
|
+ u32 message)
|
|
+#endif
|
|
+{
|
|
+ struct usbnet *dev = usb_get_intfdata(intf);
|
|
+ u16 tmp16 = 0;
|
|
+ u8 tmp8 = 0;
|
|
+
|
|
+ usbnet_suspend(intf, message);
|
|
+
|
|
+ /* Disable RX path */
|
|
+ ax88179_read_cmd_nopm(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
|
|
+ 2, 2, &tmp16, 1);
|
|
+ tmp16 &= ~AX_MEDIUM_RECEIVE_EN;
|
|
+ ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
|
|
+ 2, 2, &tmp16);
|
|
+
|
|
+ /* Force bz */
|
|
+ ax88179_read_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL,
|
|
+ 2, 2, &tmp16, 1);
|
|
+ tmp16 |= AX_PHYPWR_RSTCTL_BZ | AX_PHYPWR_RSTCTL_IPRL;
|
|
+ ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL,
|
|
+ 2, 2, &tmp16);
|
|
+
|
|
+ /* change clock */
|
|
+ tmp8 = 0;
|
|
+ ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8);
|
|
+
|
|
+ /* Configure RX control register => stop operation */
|
|
+ tmp16 = AX_RX_CTL_STOP;
|
|
+ ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &tmp16);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+
|
|
+static void ax88179_EEE_setting(struct usbnet *dev)
|
|
+{
|
|
+ u16 tmp16;
|
|
+
|
|
+ if (bEEE) {
|
|
+ // Enable EEE
|
|
+ tmp16 = 0x07;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ GMII_PHY_MACR, 2, &tmp16);
|
|
+
|
|
+ tmp16 = 0x3c;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ GMII_PHY_MAADR, 2, &tmp16);
|
|
+
|
|
+ tmp16 = 0x4007;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ GMII_PHY_MACR, 2, &tmp16);
|
|
+
|
|
+ tmp16 = 0x06;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ GMII_PHY_MAADR, 2, &tmp16);
|
|
+ } else {
|
|
+ // Disable EEE
|
|
+ tmp16 = 0x07;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ GMII_PHY_MACR, 2, &tmp16);
|
|
+
|
|
+ tmp16 = 0x3c;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ GMII_PHY_MAADR, 2, &tmp16);
|
|
+
|
|
+ tmp16 = 0x4007;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ GMII_PHY_MACR, 2, &tmp16);
|
|
+
|
|
+ tmp16 = 0x00;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ GMII_PHY_MAADR, 2, &tmp16);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void ax88179_Gether_setting(struct usbnet *dev)
|
|
+{
|
|
+
|
|
+ u16 tmp16;
|
|
+
|
|
+ if (bGETH) {
|
|
+ // Enable Green Ethernet
|
|
+ tmp16 = 0x03;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ 31, 2, &tmp16);
|
|
+
|
|
+ tmp16 = 0x3247;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ 25, 2, &tmp16);
|
|
+
|
|
+ tmp16 = 0x05;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ 31, 2, &tmp16);
|
|
+
|
|
+ tmp16 = 0x0680;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ 1, 2, &tmp16);
|
|
+
|
|
+ tmp16 = 0;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ 31, 2, &tmp16);
|
|
+ } else {
|
|
+ // Disable Green Ethernet
|
|
+ tmp16 = 0x03;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ 31, 2, &tmp16);
|
|
+
|
|
+ tmp16 = 0x3246;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ 25, 2, &tmp16);
|
|
+
|
|
+ tmp16 = 0;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ 31, 2, &tmp16);
|
|
+ }
|
|
+}
|
|
+
|
|
+static int ax88179_resume(struct usb_interface *intf)
|
|
+{
|
|
+ struct usbnet *dev = usb_get_intfdata(intf);
|
|
+ u16 tmp16 = 0;
|
|
+ u8 tmp8 = 0;
|
|
+
|
|
+ netif_carrier_off(dev->net);
|
|
+
|
|
+ /* Power up ethernet PHY */
|
|
+ tmp16 = 0;
|
|
+ ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL,
|
|
+ 2, 2, &tmp16);
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
|
|
+ usleep_range(1000, 2000);
|
|
+#else
|
|
+ msleep(1);
|
|
+#endif
|
|
+ tmp16 = AX_PHYPWR_RSTCTL_IPRL;
|
|
+ ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL,
|
|
+ 2, 2, &tmp16);
|
|
+ msleep(200);
|
|
+
|
|
+ /* Ethernet PHY Auto Detach*/
|
|
+ ax88179_AutoDetach(dev, 1);
|
|
+
|
|
+ /* change clock */
|
|
+ ax88179_read_cmd_nopm(dev, AX_ACCESS_MAC, AX_CLK_SELECT,
|
|
+ 1, 1, &tmp8, 0);
|
|
+ tmp8 |= AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS;
|
|
+ ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8);
|
|
+ msleep(100);
|
|
+
|
|
+ /* Configure RX control register => start operation */
|
|
+ tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_START | AX_RX_CTL_AP |
|
|
+ AX_RX_CTL_AMALL | AX_RX_CTL_AB;
|
|
+ if (NET_IP_ALIGN == 0)
|
|
+ tmp16 |= AX_RX_CTL_IPE;
|
|
+ ax88179_write_cmd_nopm(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &tmp16);
|
|
+
|
|
+ return usbnet_resume(intf);
|
|
+}
|
|
+
|
|
+static void
|
|
+ax88179_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
|
|
+{
|
|
+
|
|
+ struct usbnet *dev = netdev_priv(net);
|
|
+ u8 *opt = NULL;
|
|
+
|
|
+ opt = kmalloc(1, GFP_KERNEL);
|
|
+ if (!opt)
|
|
+ return;
|
|
+
|
|
+ if (ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MODE,
|
|
+ 1, 1, opt, 0) < 0) {
|
|
+ wolinfo->supported = 0;
|
|
+ wolinfo->wolopts = 0;
|
|
+ kfree(opt);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
|
|
+
|
|
+ if (*opt & AX_MONITOR_MODE_RWLC)
|
|
+ wolinfo->wolopts |= WAKE_PHY;
|
|
+ if (*opt & AX_MONITOR_MODE_RWMP)
|
|
+ wolinfo->wolopts |= WAKE_MAGIC;
|
|
+
|
|
+ kfree(opt);
|
|
+}
|
|
+
|
|
+static int
|
|
+ax88179_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
|
|
+{
|
|
+ struct usbnet *dev = netdev_priv(net);
|
|
+ u8 *opt = NULL;
|
|
+
|
|
+ opt = kmalloc(1, GFP_KERNEL);
|
|
+ if (!opt)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ *opt = 0;
|
|
+
|
|
+ if (wolinfo->wolopts & WAKE_PHY)
|
|
+ *opt |= AX_MONITOR_MODE_RWLC;
|
|
+ else
|
|
+ *opt &= ~AX_MONITOR_MODE_RWLC;
|
|
+
|
|
+ if (wolinfo->wolopts & WAKE_MAGIC)
|
|
+ *opt |= AX_MONITOR_MODE_RWMP;
|
|
+ else
|
|
+ *opt &= ~AX_MONITOR_MODE_RWMP;
|
|
+
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MODE, 1, 1, opt);
|
|
+
|
|
+ kfree(opt);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int ax88179_get_eeprom_len(struct net_device *net)
|
|
+{
|
|
+ return AX_EEPROM_LEN;
|
|
+}
|
|
+
|
|
+static int
|
|
+ax88179_get_eeprom(struct net_device *net, struct ethtool_eeprom *eeprom,
|
|
+ u8 *data)
|
|
+{
|
|
+ struct usbnet *dev = netdev_priv(net);
|
|
+ u16 *eeprom_buff = NULL;
|
|
+ int first_word = 0, last_word = 0;
|
|
+ int i = 0;
|
|
+
|
|
+ if (eeprom->len == 0)
|
|
+ return -EINVAL;
|
|
+
|
|
+ eeprom->magic = AX88179_EEPROM_MAGIC;
|
|
+
|
|
+ first_word = eeprom->offset >> 1;
|
|
+ last_word = (eeprom->offset + eeprom->len - 1) >> 1;
|
|
+ eeprom_buff = kmalloc(sizeof(u16) * (last_word - first_word + 1),
|
|
+ GFP_KERNEL);
|
|
+ if (!eeprom_buff)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ /* ax88179/178A returns 2 bytes from eeprom on read */
|
|
+ for (i = first_word; i <= last_word; i++) {
|
|
+ if (ax88179_read_cmd(dev, AX_ACCESS_EEPROM, i, 1, 2,
|
|
+ &(eeprom_buff[i - first_word]), 0) < 0) {
|
|
+ kfree(eeprom_buff);
|
|
+ return -EIO;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ memcpy(data, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len);
|
|
+ kfree(eeprom_buff);
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static void ax88179_get_drvinfo(struct net_device *net,
|
|
+ struct ethtool_drvinfo *info)
|
|
+{
|
|
+ /* Inherit standard device info */
|
|
+ usbnet_get_drvinfo(net, info);
|
|
+ info->eedump_len = 0x3e;
|
|
+}
|
|
+
|
|
+static int ax88179_get_settings(struct net_device *net, struct ethtool_cmd *cmd)
|
|
+{
|
|
+ struct usbnet *dev = netdev_priv(net);
|
|
+ return mii_ethtool_gset(&dev->mii, cmd);
|
|
+}
|
|
+
|
|
+static int ax88179_set_settings(struct net_device *net, struct ethtool_cmd *cmd)
|
|
+{
|
|
+ struct usbnet *dev = netdev_priv(net);
|
|
+ return mii_ethtool_sset(&dev->mii, cmd);
|
|
+}
|
|
+
|
|
+static int ax88179_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
|
|
+{
|
|
+ struct usbnet *dev = netdev_priv(net);
|
|
+ return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
|
|
+}
|
|
+
|
|
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 28)
|
|
+static int ax88179_netdev_stop(struct net_device *net)
|
|
+{
|
|
+ struct usbnet *dev = netdev_priv(net);
|
|
+ u16 tmp16 = 0;
|
|
+
|
|
+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
|
|
+ 2, 2, &tmp16, 1);
|
|
+ tmp16 &= ~AX_MEDIUM_RECEIVE_EN;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
|
|
+ 2, 2, &tmp16);
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
+
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
|
|
+static int ax88179_set_csums(struct usbnet *dev)
|
|
+{
|
|
+ struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data;
|
|
+ u8 checksum = 0;
|
|
+
|
|
+ if (ax179_data->checksum & AX_RX_CHECKSUM)
|
|
+ checksum = AX_RXCOE_DEF_CSUM;
|
|
+ else
|
|
+ checksum = 0;
|
|
+
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, &checksum);
|
|
+
|
|
+ if (ax179_data->checksum & AX_TX_CHECKSUM)
|
|
+ checksum = AX_TXCOE_DEF_CSUM;
|
|
+ else
|
|
+ checksum = 0;
|
|
+
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, &checksum);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static u32 ax88179_get_tx_csum(struct net_device *netdev)
|
|
+{
|
|
+ struct usbnet *dev = netdev_priv(netdev);
|
|
+ struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data;
|
|
+ return ax179_data->checksum & AX_TX_CHECKSUM;
|
|
+}
|
|
+
|
|
+static u32 ax88179_get_rx_csum(struct net_device *netdev)
|
|
+{
|
|
+ struct usbnet *dev = netdev_priv(netdev);
|
|
+ struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data;
|
|
+ return ax179_data->checksum & AX_RX_CHECKSUM;
|
|
+}
|
|
+
|
|
+static int ax88179_set_rx_csum(struct net_device *netdev, u32 val)
|
|
+{
|
|
+ struct usbnet *dev = netdev_priv(netdev);
|
|
+ struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data;
|
|
+
|
|
+ if (val)
|
|
+ ax179_data->checksum |= AX_RX_CHECKSUM;
|
|
+ else
|
|
+ ax179_data->checksum &= ~AX_RX_CHECKSUM;
|
|
+ return ax88179_set_csums(dev);
|
|
+}
|
|
+
|
|
+static int ax88179_set_tx_csum(struct net_device *netdev, u32 val)
|
|
+{
|
|
+ struct usbnet *dev = netdev_priv(netdev);
|
|
+ struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data;
|
|
+
|
|
+ if (val)
|
|
+ ax179_data->checksum |= AX_TX_CHECKSUM;
|
|
+ else
|
|
+ ax179_data->checksum &= ~AX_TX_CHECKSUM;
|
|
+
|
|
+ ethtool_op_set_tx_csum(netdev, val);
|
|
+
|
|
+ return ax88179_set_csums(dev);
|
|
+}
|
|
+
|
|
+static int ax88179_set_tso(struct net_device *netdev, u32 data)
|
|
+{
|
|
+ if (data)
|
|
+ netdev->features |= NETIF_F_TSO;
|
|
+ else
|
|
+ netdev->features &= ~NETIF_F_TSO;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
+
|
|
+static struct ethtool_ops ax88179_ethtool_ops = {
|
|
+ .get_drvinfo = ax88179_get_drvinfo,
|
|
+ .get_link = ethtool_op_get_link,
|
|
+ .get_msglevel = usbnet_get_msglevel,
|
|
+ .set_msglevel = usbnet_set_msglevel,
|
|
+ .get_wol = ax88179_get_wol,
|
|
+ .set_wol = ax88179_set_wol,
|
|
+ .get_eeprom_len = ax88179_get_eeprom_len,
|
|
+ .get_eeprom = ax88179_get_eeprom,
|
|
+ .get_settings = ax88179_get_settings,
|
|
+ .set_settings = ax88179_set_settings,
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 3, 0)
|
|
+ .set_tx_csum = ax88179_set_tx_csum,
|
|
+ .get_tx_csum = ax88179_get_tx_csum,
|
|
+ .get_rx_csum = ax88179_get_rx_csum,
|
|
+ .set_rx_csum = ax88179_set_rx_csum,
|
|
+ .get_tso = ethtool_op_get_tso,
|
|
+ .set_tso = ax88179_set_tso,
|
|
+ .get_sg = ethtool_op_get_sg,
|
|
+ .set_sg = ethtool_op_set_sg
|
|
+#endif
|
|
+};
|
|
+
|
|
+static void ax88179_set_multicast(struct net_device *net)
|
|
+{
|
|
+ struct usbnet *dev = netdev_priv(net);
|
|
+ struct ax88179_data *data = (struct ax88179_data *)&dev->data;
|
|
+ u8 *m_filter = ((u8 *)dev->data) + 12;
|
|
+ int mc_count = 0;
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
|
+ mc_count = net->mc_count;
|
|
+#else
|
|
+ mc_count = netdev_mc_count(net);
|
|
+#endif
|
|
+
|
|
+ data->rxctl = (AX_RX_CTL_START | AX_RX_CTL_AB);
|
|
+ if (NET_IP_ALIGN == 0)
|
|
+ data->rxctl |= AX_RX_CTL_IPE;
|
|
+
|
|
+ if (net->flags & IFF_PROMISC) {
|
|
+ data->rxctl |= AX_RX_CTL_PRO;
|
|
+ } else if (net->flags & IFF_ALLMULTI
|
|
+ || mc_count > AX_MAX_MCAST) {
|
|
+ data->rxctl |= AX_RX_CTL_AMALL;
|
|
+ } else if (mc_count == 0) {
|
|
+ /* just broadcast and directed */
|
|
+ } else {
|
|
+ /* We use the 20 byte dev->data
|
|
+ * for our 8 byte filter buffer
|
|
+ * to avoid allocating memory that
|
|
+ * is tricky to free later */
|
|
+ u32 crc_bits = 0;
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 35)
|
|
+ struct dev_mc_list *mc_list = net->mc_list;
|
|
+ int i = 0;
|
|
+
|
|
+ memset(m_filter, 0, AX_MCAST_FILTER_SIZE);
|
|
+
|
|
+ /* Build the multicast hash filter. */
|
|
+ for (i = 0; i < net->mc_count; i++) {
|
|
+ crc_bits =
|
|
+ ether_crc(ETH_ALEN,
|
|
+ mc_list->dmi_addr) >> 26;
|
|
+ *(m_filter + (crc_bits >> 3)) |=
|
|
+ 1 << (crc_bits & 7);
|
|
+ mc_list = mc_list->next;
|
|
+ }
|
|
+#else
|
|
+ struct netdev_hw_addr *ha = NULL;
|
|
+ memset(m_filter, 0, AX_MCAST_FILTER_SIZE);
|
|
+ netdev_for_each_mc_addr(ha, net) {
|
|
+ crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
|
|
+ *(m_filter + (crc_bits >> 3)) |=
|
|
+ 1 << (crc_bits & 7);
|
|
+ }
|
|
+#endif
|
|
+ ax88179_write_cmd_async(dev, AX_ACCESS_MAC,
|
|
+ AX_MULTI_FILTER_ARRY,
|
|
+ AX_MCAST_FILTER_SIZE,
|
|
+ AX_MCAST_FILTER_SIZE, m_filter);
|
|
+
|
|
+ data->rxctl |= AX_RX_CTL_AM;
|
|
+ }
|
|
+
|
|
+ ax88179_write_cmd_async(dev, AX_ACCESS_MAC, AX_RX_CTL,
|
|
+ 2, 2, &data->rxctl);
|
|
+}
|
|
+
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
|
|
+static int
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
|
|
+ax88179_set_features(struct net_device *net, netdev_features_t features)
|
|
+#else
|
|
+ax88179_set_features(struct net_device *net, u32 features)
|
|
+#endif
|
|
+
|
|
+{
|
|
+ u8 tmp = 0;
|
|
+ struct usbnet *dev = netdev_priv(net);
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 3, 0)
|
|
+ netdev_features_t changed = net->features ^ features;
|
|
+#else
|
|
+ u32 changed = net->features ^ features;
|
|
+#endif
|
|
+
|
|
+ if (changed & NETIF_F_IP_CSUM) {
|
|
+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL,
|
|
+ 1, 1, &tmp, 0);
|
|
+ tmp ^= AX_TXCOE_TCP | AX_TXCOE_UDP;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, &tmp);
|
|
+ }
|
|
+
|
|
+ if (changed & NETIF_F_IPV6_CSUM) {
|
|
+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL,
|
|
+ 1, 1, &tmp, 0);
|
|
+ tmp ^= AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, &tmp);
|
|
+ }
|
|
+
|
|
+ if (changed & NETIF_F_RXCSUM) {
|
|
+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL,
|
|
+ 1, 1, &tmp, 0);
|
|
+ tmp ^= AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
|
|
+ AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, &tmp);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
+
|
|
+static int ax88179_change_mtu(struct net_device *net, int new_mtu)
|
|
+{
|
|
+ struct usbnet *dev = netdev_priv(net);
|
|
+ u16 tmp16 = 0;
|
|
+
|
|
+ if (new_mtu <= 0 || new_mtu > 4088)
|
|
+ return -EINVAL;
|
|
+
|
|
+ net->mtu = new_mtu;
|
|
+ dev->hard_mtu = net->mtu + net->hard_header_len;
|
|
+
|
|
+ if (net->mtu > 1500) {
|
|
+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
|
|
+ 2, 2, &tmp16, 1);
|
|
+ tmp16 |= AX_MEDIUM_JUMBO_EN;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
|
|
+ 2, 2, &tmp16);
|
|
+ } else {
|
|
+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
|
|
+ 2, 2, &tmp16, 1);
|
|
+ tmp16 &= ~AX_MEDIUM_JUMBO_EN;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
|
|
+ 2, 2, &tmp16);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int ax88179_set_mac_addr(struct net_device *net, void *p)
|
|
+{
|
|
+ struct usbnet *dev = netdev_priv(net);
|
|
+ struct sockaddr *addr = p;
|
|
+
|
|
+ if (netif_running(net))
|
|
+ return -EBUSY;
|
|
+ if (!is_valid_ether_addr(addr->sa_data))
|
|
+ return -EADDRNOTAVAIL;
|
|
+
|
|
+ memcpy(net->dev_addr, addr->sa_data, ETH_ALEN);
|
|
+
|
|
+ /* Set the MAC address */
|
|
+ return ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN,
|
|
+ ETH_ALEN, net->dev_addr);
|
|
+
|
|
+}
|
|
+
|
|
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 29)
|
|
+static const struct net_device_ops ax88179_netdev_ops = {
|
|
+ .ndo_open = usbnet_open,
|
|
+ .ndo_stop = usbnet_stop,
|
|
+ .ndo_start_xmit = usbnet_start_xmit,
|
|
+ .ndo_tx_timeout = usbnet_tx_timeout,
|
|
+ .ndo_change_mtu = ax88179_change_mtu,
|
|
+ .ndo_do_ioctl = ax88179_ioctl,
|
|
+ .ndo_set_mac_address = ax88179_set_mac_addr,
|
|
+ .ndo_validate_addr = eth_validate_addr,
|
|
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(3, 2, 0)
|
|
+ .ndo_set_multicast_list = ax88179_set_multicast,
|
|
+#else
|
|
+ .ndo_set_rx_mode = ax88179_set_multicast,
|
|
+#endif
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
|
|
+ .ndo_set_features = ax88179_set_features,
|
|
+#endif
|
|
+};
|
|
+#endif
|
|
+
|
|
+static int ax88179_check_eeprom(struct usbnet *dev)
|
|
+{
|
|
+ u8 i = 0;
|
|
+ u8 buf[2] = {0};
|
|
+ u8 eeprom[20] = {0};
|
|
+ u16 csum = 0, delay = HZ / 10;
|
|
+ unsigned long jtimeout = 0;
|
|
+
|
|
+ /* Read EEPROM content */
|
|
+ for (i = 0 ; i < 6; i++) {
|
|
+
|
|
+ buf[0] = i;
|
|
+ if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_ADDR,
|
|
+ 1, 1, buf) < 0)
|
|
+ return -EINVAL;
|
|
+
|
|
+ buf[0] = EEP_RD;
|
|
+ if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD,
|
|
+ 1, 1, buf) < 0)
|
|
+ return -EINVAL;
|
|
+
|
|
+ jtimeout = jiffies + delay;
|
|
+ do {
|
|
+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD,
|
|
+ 1, 1, buf, 0);
|
|
+
|
|
+ if (time_after(jiffies, jtimeout))
|
|
+ return -EINVAL;
|
|
+ } while (buf[0] & EEP_BUSY);
|
|
+
|
|
+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_DATA_LOW,
|
|
+ 2, 2, &eeprom[i * 2], 0);
|
|
+
|
|
+ if ((i == 0) && (eeprom[0] == 0xFF))
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ csum = eeprom[6] + eeprom[7] + eeprom[8] + eeprom[9];
|
|
+ csum = (csum >> 8) + (csum & 0xff);
|
|
+
|
|
+ if ((csum + eeprom[10]) == 0xff)
|
|
+ return AX_EEP_EFUSE_CORRECT;
|
|
+ else
|
|
+ return -EINVAL;
|
|
+}
|
|
+
|
|
+static int ax88179_check_efuse(struct usbnet *dev, void *ledmode)
|
|
+{
|
|
+ u8 i = 0;
|
|
+ u8 efuse[64] = {0x00};
|
|
+ u16 csum = 0;
|
|
+
|
|
+ if (ax88179_read_cmd(dev, AX_ACCESS_EFUSE, 0, 64, 64, efuse, 0) < 0)
|
|
+ return -EINVAL;
|
|
+
|
|
+ if (efuse[0] == 0xFF)
|
|
+ return -EINVAL;
|
|
+
|
|
+ for (i = 0; i < 64; i++)
|
|
+ csum = csum + efuse[i];
|
|
+
|
|
+ while (csum > 255)
|
|
+ csum = (csum & 0x00FF) + ((csum >> 8) & 0x00FF);
|
|
+
|
|
+ if (csum == 0xFF) {
|
|
+ memcpy((u8 *)ledmode, &efuse[51], 2);
|
|
+ return AX_EEP_EFUSE_CORRECT;
|
|
+ } else {
|
|
+ return -EINVAL;
|
|
+ }
|
|
+}
|
|
+
|
|
+static int ax88179_convert_old_led(struct usbnet *dev, u8 efuse, void *ledvalue)
|
|
+{
|
|
+ u8 ledmode = 0;
|
|
+ u16 tmp = 0;
|
|
+ u16 led = 0;
|
|
+
|
|
+ /* loaded the old eFuse LED Mode */
|
|
+ if (efuse) {
|
|
+ if (ax88179_read_cmd(dev, AX_ACCESS_EFUSE, 0x18,
|
|
+ 1, 2, &tmp, 1) < 0)
|
|
+ return -EINVAL;
|
|
+ ledmode = (u8)(tmp & 0xFF);
|
|
+ } else { /* loaded the old EEprom LED Mode */
|
|
+ if (ax88179_read_cmd(dev, AX_ACCESS_EEPROM, 0x3C,
|
|
+ 1, 2, &tmp, 1) < 0)
|
|
+ return -EINVAL;
|
|
+ ledmode = (u8) (tmp >> 8);
|
|
+ }
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
|
|
+ netdev_dbg(dev->net, "Old LED Mode = %02X\n", ledmode);
|
|
+#else
|
|
+ devdbg(dev, "Old LED Mode = %02X\n", ledmode);
|
|
+#endif
|
|
+ switch (ledmode) {
|
|
+ case 0xFF:
|
|
+ led = LED0_ACTIVE | LED1_LINK_10 | LED1_LINK_100 |
|
|
+ LED1_LINK_1000 | LED2_ACTIVE | LED2_LINK_10 |
|
|
+ LED2_LINK_100 | LED2_LINK_1000 | LED_VALID;
|
|
+ break;
|
|
+ case 0xFE:
|
|
+ led = LED0_ACTIVE | LED1_LINK_1000 | LED2_LINK_100 | LED_VALID;
|
|
+ break;
|
|
+ case 0xFD:
|
|
+ led = LED0_ACTIVE | LED1_LINK_1000 | LED2_LINK_100 |
|
|
+ LED2_LINK_10 | LED_VALID;
|
|
+ break;
|
|
+ case 0xFC:
|
|
+ led = LED0_ACTIVE | LED1_ACTIVE | LED1_LINK_1000 | LED2_ACTIVE |
|
|
+ LED2_LINK_100 | LED2_LINK_10 | LED_VALID;
|
|
+ break;
|
|
+ default:
|
|
+ led = LED0_ACTIVE | LED1_LINK_10 | LED1_LINK_100 |
|
|
+ LED1_LINK_1000 | LED2_ACTIVE | LED2_LINK_10 |
|
|
+ LED2_LINK_100 | LED2_LINK_1000 | LED_VALID;
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ memcpy((u8 *)ledvalue, &led, 2);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int ax88179_led_setting(struct usbnet *dev)
|
|
+{
|
|
+ u8 ledfd = 0, value = 0;
|
|
+ u16 tmp = 0, ledact = 0, ledlink = 0, ledvalue = 0, delay = HZ / 10;
|
|
+ unsigned long jtimeout = 0;
|
|
+
|
|
+ /* Check AX88179 version. UA1 or UA2 */
|
|
+ ax88179_read_cmd(dev, AX_ACCESS_MAC, GENERAL_STATUS, 1, 1, &value, 0);
|
|
+
|
|
+ /* UA1 */
|
|
+ if (!(value & AX_SECLD)) {
|
|
+ value = AX_GPIO_CTRL_GPIO3EN | AX_GPIO_CTRL_GPIO2EN |
|
|
+ AX_GPIO_CTRL_GPIO1EN;
|
|
+ if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_GPIO_CTRL,
|
|
+ 1, 1, &value) < 0)
|
|
+ return -EINVAL;
|
|
+ }
|
|
+
|
|
+ /* check EEprom */
|
|
+ if (ax88179_check_eeprom(dev) == AX_EEP_EFUSE_CORRECT) {
|
|
+ value = 0x42;
|
|
+ if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_ADDR,
|
|
+ 1, 1, &value) < 0)
|
|
+ return -EINVAL;
|
|
+
|
|
+ value = EEP_RD;
|
|
+ if (ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD,
|
|
+ 1, 1, &value) < 0)
|
|
+ return -EINVAL;
|
|
+
|
|
+ jtimeout = jiffies + delay;
|
|
+ do {
|
|
+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD,
|
|
+ 1, 1, &value, 0);
|
|
+
|
|
+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_CMD,
|
|
+ 1, 1, &value, 0);
|
|
+
|
|
+ if (time_after(jiffies, jtimeout))
|
|
+ return -EINVAL;
|
|
+ } while (value & EEP_BUSY);
|
|
+
|
|
+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_DATA_HIGH,
|
|
+ 1, 1, &value, 0);
|
|
+ ledvalue = (value << 8);
|
|
+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_SROM_DATA_LOW,
|
|
+ 1, 1, &value, 0);
|
|
+ ledvalue |= value;
|
|
+
|
|
+ /* load internal ROM for defaule setting */
|
|
+ if ((ledvalue == 0xFFFF) || ((ledvalue & LED_VALID) == 0))
|
|
+ ax88179_convert_old_led(dev, 0, &ledvalue);
|
|
+
|
|
+ } else if (ax88179_check_efuse(dev, &ledvalue) ==
|
|
+ AX_EEP_EFUSE_CORRECT) { /* check efuse */
|
|
+ if ((ledvalue == 0xFFFF) || ((ledvalue & LED_VALID) == 0))
|
|
+ ax88179_convert_old_led(dev, 0, &ledvalue);
|
|
+ } else {
|
|
+ ax88179_convert_old_led(dev, 0, &ledvalue);
|
|
+ }
|
|
+
|
|
+ tmp = GMII_PHY_PAGE_SELECT_EXT;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ GMII_PHY_PAGE_SELECT, 2, &tmp);
|
|
+
|
|
+ tmp = 0x2c;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ GMII_PHYPAGE, 2, &tmp);
|
|
+
|
|
+ ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ GMII_LED_ACTIVE, 2, &ledact, 1);
|
|
+
|
|
+ ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ GMII_LED_LINK, 2, &ledlink, 1);
|
|
+
|
|
+ ledact &= GMII_LED_ACTIVE_MASK;
|
|
+ ledlink &= GMII_LED_LINK_MASK;
|
|
+
|
|
+ if (ledvalue & LED0_ACTIVE)
|
|
+ ledact |= GMII_LED0_ACTIVE;
|
|
+ if (ledvalue & LED1_ACTIVE)
|
|
+ ledact |= GMII_LED1_ACTIVE;
|
|
+ if (ledvalue & LED2_ACTIVE)
|
|
+ ledact |= GMII_LED2_ACTIVE;
|
|
+
|
|
+ if (ledvalue & LED0_LINK_10)
|
|
+ ledlink |= GMII_LED0_LINK_10;
|
|
+ if (ledvalue & LED1_LINK_10)
|
|
+ ledlink |= GMII_LED1_LINK_10;
|
|
+ if (ledvalue & LED2_LINK_10)
|
|
+ ledlink |= GMII_LED2_LINK_10;
|
|
+
|
|
+ if (ledvalue & LED0_LINK_100)
|
|
+ ledlink |= GMII_LED0_LINK_100;
|
|
+ if (ledvalue & LED1_LINK_100)
|
|
+ ledlink |= GMII_LED1_LINK_100;
|
|
+ if (ledvalue & LED2_LINK_100)
|
|
+ ledlink |= GMII_LED2_LINK_100;
|
|
+
|
|
+ if (ledvalue & LED0_LINK_1000)
|
|
+ ledlink |= GMII_LED0_LINK_1000;
|
|
+ if (ledvalue & LED1_LINK_1000)
|
|
+ ledlink |= GMII_LED1_LINK_1000;
|
|
+ if (ledvalue & LED2_LINK_1000)
|
|
+ ledlink |= GMII_LED2_LINK_1000;
|
|
+
|
|
+ tmp = ledact;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ GMII_LED_ACTIVE, 2, &tmp);
|
|
+
|
|
+ tmp = ledlink;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ GMII_LED_LINK, 2, &tmp);
|
|
+
|
|
+ tmp = GMII_PHY_PAGE_SELECT_PAGE0;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ GMII_PHY_PAGE_SELECT, 2, &tmp);
|
|
+
|
|
+ /* LED full duplex setting */
|
|
+ ledfd = 0;
|
|
+ if (ledvalue & LED0_FD)
|
|
+ ledfd |= 0x01;
|
|
+ else if ((ledvalue & LED0_USB3_MASK) == 0)
|
|
+ ledfd |= 0x02;
|
|
+
|
|
+
|
|
+ if (ledvalue & LED1_FD)
|
|
+ ledfd |= 0x04;
|
|
+ else if ((ledvalue & LED1_USB3_MASK) == 0)
|
|
+ ledfd |= 0x08;
|
|
+
|
|
+ if (ledvalue & LED2_FD) /* LED2_FD */
|
|
+ ledfd |= 0x10;
|
|
+ else if ((ledvalue & LED2_USB3_MASK) == 0) /* LED2_USB3 */
|
|
+ ledfd |= 0x20;
|
|
+
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, 0x73, 1, 1, &ledfd);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int ax88179_AutoDetach(struct usbnet *dev, int in_pm)
|
|
+{
|
|
+ u16 tmp16 = 0;
|
|
+ u8 tmp8 = 0;
|
|
+ int (*fnr)(struct usbnet *, u8, u16, u16, u16, void *, int);
|
|
+ int (*fnw)(struct usbnet *, u8, u16, u16, u16, void *);
|
|
+
|
|
+ if (!in_pm) {
|
|
+ fnr = ax88179_read_cmd;
|
|
+ fnw = ax88179_write_cmd;
|
|
+ } else {
|
|
+ fnr = ax88179_read_cmd_nopm;
|
|
+ fnw = ax88179_write_cmd_nopm;
|
|
+ }
|
|
+
|
|
+ if (fnr(dev, AX_ACCESS_EEPROM, 0x43, 1, 2, &tmp16, 1) < 0)
|
|
+ return 0;
|
|
+
|
|
+ if ((tmp16 == 0xFFFF) || (!(tmp16 & 0x0100)))
|
|
+ return 0;
|
|
+
|
|
+ /* Enable Auto Detach bit */
|
|
+ tmp8 = 0;
|
|
+ fnr(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8, 0);
|
|
+ tmp8 |= AX_CLK_SELECT_ULR;
|
|
+ fnw(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, &tmp8);
|
|
+
|
|
+ fnr(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, &tmp16, 1);
|
|
+ tmp16 |= AX_PHYPWR_RSTCTL_AUTODETACH;
|
|
+ fnw(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, &tmp16);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int access_eeprom_mac(struct usbnet *dev, u8 *buf, u8 offset, bool wflag)
|
|
+{
|
|
+ int ret = 0, i;
|
|
+ u16* tmp = (u16*)buf;
|
|
+
|
|
+ for (i = 0; i < (ETH_ALEN >> 1); i++) {
|
|
+ if (wflag) {
|
|
+ u16 wd = cpu_to_le16(*(tmp + i));
|
|
+ ret = ax88179_write_cmd(dev, AX_ACCESS_EEPROM,
|
|
+ offset + i, 1, 2, &wd);
|
|
+ if (ret < 0)
|
|
+ break;
|
|
+
|
|
+ mdelay(15);
|
|
+ }
|
|
+ else {
|
|
+ ret = ax88179_read_cmd(dev, AX_ACCESS_EEPROM,
|
|
+ offset + i, 1, 2, tmp + i, 0);
|
|
+ if (ret < 0)
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (!wflag) {
|
|
+ if (ret < 0) {
|
|
+ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
|
|
+ netdev_dbg(dev->net, "Failed to read MAC address from EEPROM: %d\n", ret);
|
|
+ #else
|
|
+ devdbg(dev, "Failed to read MAC address from EEPROM: %d\n", ret);
|
|
+ #endif
|
|
+ return ret;
|
|
+ }
|
|
+ memcpy(dev->net->dev_addr, buf, ETH_ALEN);
|
|
+ }
|
|
+ else {
|
|
+ /* reload eeprom data */
|
|
+ ret = ax88179_write_cmd(dev, AX_RELOAD_EEPROM_EFUSE, 0, 0, 0, 0);
|
|
+ if (ret < 0)
|
|
+ return ret;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int ax88179_check_ether_addr(struct usbnet *dev)
|
|
+{
|
|
+ unsigned char *tmp = (unsigned char*)dev->net->dev_addr;
|
|
+ u8 default_mac[6] = {0, 0x0e, 0xc6, 0x81, 0x79, 0x01};
|
|
+ u8 default_mac_178a[6] = {0, 0x0e, 0xc6, 0x81, 0x78, 0x01};
|
|
+
|
|
+ if (((*((u8*)tmp) == 0) && (*((u8*)tmp + 1) == 0) && (*((u8*)tmp + 2) == 0)) ||
|
|
+ !is_valid_ether_addr((u8*)tmp) ||
|
|
+ !memcmp(dev->net->dev_addr, default_mac, ETH_ALEN) ||
|
|
+ !memcmp(dev->net->dev_addr, default_mac_178a, ETH_ALEN)) {
|
|
+ int i;
|
|
+
|
|
+ printk("Found invalid EEPROM MAC address value ");
|
|
+
|
|
+ for (i = 0; i < ETH_ALEN; i++) {
|
|
+ printk("%02X", *((u8*)tmp + i));
|
|
+ if (i != 5)
|
|
+ printk("-");
|
|
+ }
|
|
+ printk("\n");
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 4, 0)
|
|
+ eth_hw_addr_random(dev->net);
|
|
+#else
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 36)
|
|
+ dev->net->addr_assign_type |= NET_ADDR_RANDOM;
|
|
+#endif
|
|
+ random_ether_addr(dev->net->dev_addr);
|
|
+#endif
|
|
+ *tmp = 0;
|
|
+ *(tmp + 1) = 0x0E;
|
|
+ *(tmp + 2) = 0xC6;
|
|
+ *(tmp + 3) = 0x8E;
|
|
+
|
|
+ return -EADDRNOTAVAIL;
|
|
+ }
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int ax88179_get_mac(struct usbnet *dev, u8* buf)
|
|
+{
|
|
+ int ret, i;
|
|
+
|
|
+ ret = access_eeprom_mac(dev, buf, 0x0, 0);
|
|
+ if (ret < 0)
|
|
+ goto out;
|
|
+
|
|
+ if (ax88179_check_ether_addr(dev)) {
|
|
+ ret = access_eeprom_mac(dev, dev->net->dev_addr, 0x0, 1);
|
|
+ if (ret < 0) {
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
|
|
+ netdev_err(dev->net, "Failed to write MAC to EEPROM: %d", ret);
|
|
+#else
|
|
+ deverr(dev, "Failed to write MAC to EEPROM: %d", ret);
|
|
+#endif
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ msleep(5);
|
|
+
|
|
+ ret = ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID,
|
|
+ ETH_ALEN, ETH_ALEN, buf, 0);
|
|
+ if (ret < 0) {
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
|
|
+ netdev_err(dev->net, "Failed to read MAC address: %d", ret);
|
|
+#else
|
|
+ deverr(dev, "Failed to read MAC address: %d", ret);
|
|
+#endif
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ for (i = 0; i < ETH_ALEN; i++)
|
|
+ if (*(dev->net->dev_addr + i) != *((u8*)buf + i)) {
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
|
|
+ netdev_warn(dev->net, "Found invalid EEPROM part or non-EEPROM");
|
|
+#else
|
|
+ devwarn(dev, "Found invalid EEPROM part or non-EEPROM");
|
|
+#endif
|
|
+ break;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ memcpy(dev->net->perm_addr, dev->net->dev_addr, ETH_ALEN);
|
|
+
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN,
|
|
+ ETH_ALEN, dev->net->dev_addr);
|
|
+
|
|
+ if (ret < 0) {
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
|
|
+ netdev_err(dev->net, "Failed to write MAC address: %d", ret);
|
|
+#else
|
|
+ deverr(dev, "Failed to write MAC address: %d", ret);
|
|
+#endif
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+out:
|
|
+ return ret;
|
|
+}
|
|
+
|
|
+static int ax88179_bind(struct usbnet *dev, struct usb_interface *intf)
|
|
+{
|
|
+ void *buf = NULL;
|
|
+ u16 *tmp16 = NULL;
|
|
+ u8 *tmp = NULL;
|
|
+ int ret;
|
|
+
|
|
+ struct ax88179_data *ax179_data = (struct ax88179_data *)dev->data;
|
|
+
|
|
+ usbnet_get_endpoints(dev, intf);
|
|
+
|
|
+ if (msg_enable != 0)
|
|
+ dev->msg_enable = msg_enable;
|
|
+
|
|
+ buf = kmalloc(6, GFP_KERNEL);
|
|
+ if (!buf) {
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
|
|
+ netdev_err(dev->net, "Cannot allocate memory for buffer");
|
|
+#else
|
|
+ deverr(dev, "Cannot allocate memory for buffer");
|
|
+#endif
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ tmp16 = (u16 *)buf;
|
|
+ tmp = (u8 *)buf;
|
|
+
|
|
+ memset(ax179_data, 0, sizeof(*ax179_data));
|
|
+
|
|
+ /* Power up ethernet PHY */
|
|
+ *tmp16 = 0;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
|
|
+ *tmp16 = AX_PHYPWR_RSTCTL_IPRL;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
|
|
+ msleep(200);
|
|
+
|
|
+ *tmp = AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp);
|
|
+ msleep(100);
|
|
+
|
|
+ /* Get the MAC address */
|
|
+ memset(buf, 0, ETH_ALEN);
|
|
+ ret = ax88179_get_mac(dev, buf);
|
|
+ if (ret)
|
|
+ goto out;
|
|
+
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
|
|
+ netdev_dbg(dev->net, "MAC [%02x-%02x-%02x-%02x-%02x-%02x]\n",
|
|
+ dev->net->dev_addr[0], dev->net->dev_addr[1],
|
|
+ dev->net->dev_addr[2], dev->net->dev_addr[3],
|
|
+ dev->net->dev_addr[4], dev->net->dev_addr[5]);
|
|
+#else
|
|
+ devdbg(dev, "MAC [%02x-%02x-%02x-%02x-%02x-%02x]\n",
|
|
+ dev->net->dev_addr[0], dev->net->dev_addr[1],
|
|
+ dev->net->dev_addr[2], dev->net->dev_addr[3],
|
|
+ dev->net->dev_addr[4], dev->net->dev_addr[5]);
|
|
+#endif
|
|
+
|
|
+ /* RX bulk configuration, default for USB3.0 to Giga*/
|
|
+ memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5);
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp);
|
|
+
|
|
+ dev->rx_urb_size = 1024 * 20;
|
|
+
|
|
+ tmp[0] = 0x34;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_LOW, 1, 1, tmp);
|
|
+
|
|
+ tmp[0] = 0x52;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_HIGH,
|
|
+ 1, 1, tmp);
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 30)
|
|
+ dev->net->do_ioctl = ax88179_ioctl;
|
|
+ dev->net->set_multicast_list = ax88179_set_multicast;
|
|
+ dev->net->set_mac_address = ax88179_set_mac_addr;
|
|
+ dev->net->change_mtu = ax88179_change_mtu;
|
|
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 28)
|
|
+ dev->net->stop = ax88179_netdev_stop;
|
|
+#endif
|
|
+#else
|
|
+ dev->net->netdev_ops = &ax88179_netdev_ops;
|
|
+#endif
|
|
+
|
|
+ dev->net->ethtool_ops = &ax88179_ethtool_ops;
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
|
|
+ dev->net->needed_headroom = 8;
|
|
+#endif
|
|
+
|
|
+ /* Initialize MII structure */
|
|
+ dev->mii.dev = dev->net;
|
|
+ dev->mii.mdio_read = ax88179_mdio_read;
|
|
+ dev->mii.mdio_write = ax88179_mdio_write;
|
|
+ dev->mii.phy_id_mask = 0xff;
|
|
+ dev->mii.reg_num_mask = 0xff;
|
|
+ dev->mii.phy_id = 0x03;
|
|
+ dev->mii.supports_gmii = 1;
|
|
+
|
|
+ dev->net->features |= NETIF_F_IP_CSUM;
|
|
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)
|
|
+ dev->net->features |= NETIF_F_IPV6_CSUM;
|
|
+#endif
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
|
|
+ if (usb_device_no_sg_constraint(dev->udev))
|
|
+ dev->can_dma_sg = 1;
|
|
+ dev->net->features |= NETIF_F_SG | NETIF_F_TSO;
|
|
+#endif
|
|
+
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
|
|
+ dev->net->hw_features |= NETIF_F_IP_CSUM;
|
|
+ dev->net->hw_features |= NETIF_F_IPV6_CSUM;
|
|
+ dev->net->hw_features |= NETIF_F_SG | NETIF_F_TSO;
|
|
+#endif
|
|
+
|
|
+ /* Enable checksum offload */
|
|
+ *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
|
|
+ AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, tmp);
|
|
+
|
|
+ *tmp = AX_TXCOE_IP | AX_TXCOE_TCP | AX_TXCOE_UDP |
|
|
+ AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, tmp);
|
|
+
|
|
+ ax179_data->checksum |= AX_RX_CHECKSUM | AX_TX_CHECKSUM;
|
|
+
|
|
+ /* Configure RX control register => start operation */
|
|
+ *tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_START | AX_RX_CTL_AP |
|
|
+ AX_RX_CTL_AMALL | AX_RX_CTL_AB;
|
|
+ if (NET_IP_ALIGN == 0)
|
|
+ *tmp16 |= AX_RX_CTL_IPE;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, tmp16);
|
|
+
|
|
+ *tmp = AX_MONITOR_MODE_PMETYPE | AX_MONITOR_MODE_PMEPOL |
|
|
+ AX_MONITOR_MODE_RWMP;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MODE, 1, 1, tmp);
|
|
+
|
|
+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MODE, 1, 1, tmp, 0);
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
|
|
+ netdev_dbg(dev->net, "Monitor mode = 0x%02x\n", *tmp);
|
|
+#else
|
|
+ devdbg(dev, "Monitor mode = 0x%02x\n", *tmp);
|
|
+#endif
|
|
+ /* Configure default medium type => giga */
|
|
+ *tmp16 = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN |
|
|
+ AX_MEDIUM_RXFLOW_CTRLEN | AX_MEDIUM_FULL_DUPLEX |
|
|
+ AX_MEDIUM_GIGAMODE;
|
|
+
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
|
|
+ 2, 2, tmp16);
|
|
+
|
|
+ ax88179_led_setting(dev);
|
|
+
|
|
+ ax88179_EEE_setting(dev);
|
|
+
|
|
+ ax88179_Gether_setting(dev);
|
|
+
|
|
+ /* Restart autoneg */
|
|
+ mii_nway_restart(&dev->mii);
|
|
+
|
|
+ netif_carrier_off(dev->net);
|
|
+
|
|
+ kfree(buf);
|
|
+ printk(version);
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
|
|
+ netdev_info(dev->net, "mtu %d\n", dev->net->mtu);
|
|
+#else
|
|
+ devinfo(dev, "mtu %d\n", dev->net->mtu);
|
|
+#endif
|
|
+ return 0;
|
|
+
|
|
+out:
|
|
+ kfree(buf);
|
|
+ return ret;
|
|
+
|
|
+}
|
|
+
|
|
+static void ax88179_unbind(struct usbnet *dev, struct usb_interface *intf)
|
|
+{
|
|
+ u16 tmp16 = 0;
|
|
+ u8 tmp8 = 0;
|
|
+ struct ax88179_data *ax179_data = (struct ax88179_data *) dev->data;
|
|
+
|
|
+ if (ax179_data) {
|
|
+ /* Configure RX control register => stop operation */
|
|
+ tmp16 = AX_RX_CTL_STOP;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &tmp16);
|
|
+
|
|
+ tmp8 = 0x0;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT,
|
|
+ 1, 1, &tmp8);
|
|
+
|
|
+ /* Power down ethernet PHY */
|
|
+ tmp16 = AX_PHYPWR_RSTCTL_BZ | AX_PHYPWR_RSTCTL_IPRL;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL,
|
|
+ 2, 2, &tmp16);
|
|
+ msleep(200);
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+ax88179_rx_checksum(struct sk_buff *skb, u32 *pkt_hdr)
|
|
+{
|
|
+ skb->ip_summed = CHECKSUM_NONE;
|
|
+
|
|
+ /* checksum error bit is set */
|
|
+ if ((*pkt_hdr & AX_RXHDR_L3CSUM_ERR) ||
|
|
+ (*pkt_hdr & AX_RXHDR_L4CSUM_ERR))
|
|
+ return;
|
|
+
|
|
+ /* It must be a TCP or UDP packet with a valid checksum */
|
|
+ if (((*pkt_hdr & AX_RXHDR_L4_TYPE_MASK) == AX_RXHDR_L4_TYPE_TCP) ||
|
|
+ ((*pkt_hdr & AX_RXHDR_L4_TYPE_MASK) == AX_RXHDR_L4_TYPE_UDP))
|
|
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
|
|
+}
|
|
+
|
|
+static int ax88179_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
|
|
+{
|
|
+ struct sk_buff *ax_skb = NULL;
|
|
+ int pkt_cnt = 0;
|
|
+ u32 rx_hdr = 0;
|
|
+ u16 hdr_off = 0;
|
|
+ u32 *pkt_hdr = NULL;
|
|
+
|
|
+ skb_trim(skb, skb->len - 4);
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 22)
|
|
+ memcpy(&rx_hdr, skb_tail_pointer(skb), sizeof(rx_hdr));
|
|
+#else
|
|
+ memcpy(&rx_hdr, skb->tail, sizeof(rx_hdr));
|
|
+#endif
|
|
+ le32_to_cpus(&rx_hdr);
|
|
+
|
|
+ pkt_cnt = (u16)rx_hdr;
|
|
+ hdr_off = (u16)(rx_hdr >> 16);
|
|
+ pkt_hdr = (u32 *)(skb->data + hdr_off);
|
|
+
|
|
+ while (pkt_cnt--) {
|
|
+ u16 pkt_len;
|
|
+
|
|
+ le32_to_cpus(pkt_hdr);
|
|
+ pkt_len = (*pkt_hdr >> 16) & 0x1fff;
|
|
+
|
|
+ /* Check CRC or runt packet */
|
|
+ if ((*pkt_hdr & AX_RXHDR_CRC_ERR) ||
|
|
+ (*pkt_hdr & AX_RXHDR_DROP_ERR)) {
|
|
+ skb_pull(skb, (pkt_len + 7) & 0xFFF8);
|
|
+ pkt_hdr++;
|
|
+ continue;
|
|
+ }
|
|
+
|
|
+ if (pkt_cnt == 0) {
|
|
+ skb->len = pkt_len;
|
|
+
|
|
+ /* Skip IP alignment psudo header */
|
|
+ if (NET_IP_ALIGN == 0)
|
|
+ skb_pull(skb, 2);
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
|
|
+ skb->tail = skb->data + skb->len;
|
|
+#else
|
|
+ skb_set_tail_pointer(skb, skb->len);
|
|
+#endif
|
|
+ skb->truesize = skb->len + sizeof(struct sk_buff);
|
|
+ ax88179_rx_checksum(skb, pkt_hdr);
|
|
+
|
|
+ return 1;
|
|
+ }
|
|
+
|
|
+#ifndef RX_SKB_COPY
|
|
+ ax_skb = skb_clone(skb, GFP_ATOMIC);
|
|
+#else
|
|
+ ax_skb = alloc_skb(pkt_len + NET_IP_ALIGN, GFP_ATOMIC);
|
|
+ skb_reserve(ax_skb, NET_IP_ALIGN);
|
|
+#endif
|
|
+
|
|
+ if (ax_skb) {
|
|
+#ifndef RX_SKB_COPY
|
|
+ ax_skb->len = pkt_len;
|
|
+
|
|
+ /* Skip IP alignment psudo header */
|
|
+ if (NET_IP_ALIGN == 0)
|
|
+ skb_pull(ax_skb, 2);
|
|
+
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
|
|
+ ax_skb->tail = ax_skb->data + ax_skb->len;
|
|
+#else
|
|
+ skb_set_tail_pointer(ax_skb, ax_skb->len);
|
|
+#endif
|
|
+
|
|
+#else
|
|
+ skb_put(ax_skb, pkt_len);
|
|
+ memcpy(ax_skb->data, skb->data, pkt_len);
|
|
+
|
|
+ if (NET_IP_ALIGN == 0)
|
|
+ skb_pull(ax_skb, 2);
|
|
+#endif
|
|
+ ax_skb->truesize = ax_skb->len + sizeof(struct sk_buff);
|
|
+ ax88179_rx_checksum(ax_skb, pkt_hdr);
|
|
+ usbnet_skb_return(dev, ax_skb);
|
|
+ } else {
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ skb_pull(skb, (pkt_len + 7) & 0xFFF8);
|
|
+ pkt_hdr++;
|
|
+ }
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+static struct sk_buff *
|
|
+ax88179_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
|
|
+{
|
|
+ u32 tx_hdr1 = 0, tx_hdr2 = 0;
|
|
+ int frame_size = dev->maxpacket;
|
|
+ int mss = skb_shinfo(skb)->gso_size;
|
|
+ int headroom = 0;
|
|
+ int tailroom = 0;
|
|
+
|
|
+ tx_hdr1 = skb->len;
|
|
+ tx_hdr2 = mss;
|
|
+ if (((skb->len + 8) % frame_size) == 0)
|
|
+ tx_hdr2 |= 0x80008000; /* Enable padding */
|
|
+
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
|
|
+ if (!dev->can_dma_sg && (dev->net->features & NETIF_F_SG) &&
|
|
+ skb_linearize(skb))
|
|
+ return NULL;
|
|
+#else
|
|
+ if ((dev->net->features & NETIF_F_SG) && skb_linearize(skb))
|
|
+ return NULL;
|
|
+#endif
|
|
+
|
|
+ headroom = skb_headroom(skb);
|
|
+ tailroom = skb_tailroom(skb);
|
|
+
|
|
+ if ((headroom + tailroom) >= 8) {
|
|
+ if (headroom < 8) {
|
|
+ skb->data = memmove(skb->head + 8, skb->data, skb->len);
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
|
|
+ skb->tail = skb->data + skb->len;
|
|
+#else
|
|
+ skb_set_tail_pointer(skb, skb->len);
|
|
+#endif
|
|
+ }
|
|
+ } else {
|
|
+ struct sk_buff *skb2 = NULL;
|
|
+ skb2 = skb_copy_expand(skb, 8, 0, flags);
|
|
+ dev_kfree_skb_any(skb);
|
|
+ skb = skb2;
|
|
+ if (!skb)
|
|
+ return NULL;
|
|
+ }
|
|
+
|
|
+ skb_push(skb, 4);
|
|
+ cpu_to_le32s(&tx_hdr2);
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
|
|
+ memcpy(skb->data, &tx_hdr2, 4);
|
|
+#else
|
|
+ skb_copy_to_linear_data(skb, &tx_hdr2, 4);
|
|
+#endif
|
|
+
|
|
+ skb_push(skb, 4);
|
|
+ cpu_to_le32s(&tx_hdr1);
|
|
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
|
|
+ memcpy(skb->data, &tx_hdr1, 4);
|
|
+#else
|
|
+ skb_copy_to_linear_data(skb, &tx_hdr1, 4);
|
|
+#endif
|
|
+
|
|
+ return skb;
|
|
+}
|
|
+
|
|
+static int ax88179_link_reset(struct usbnet *dev)
|
|
+{
|
|
+ struct ax88179_data *data = (struct ax88179_data *)&dev->data;
|
|
+ u8 tmp[5] = {0}, link_sts = 0;
|
|
+ u16 mode = 0, tmp16 = 0, delay = HZ/10;
|
|
+ u32 tmp32 = 0x40000000;
|
|
+ unsigned long jtimeout = 0;
|
|
+
|
|
+ jtimeout = jiffies + delay;
|
|
+
|
|
+ while (tmp32 & 0x40000000) {
|
|
+ mode = 0;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, &mode);
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL,
|
|
+ 2, 2, &data->rxctl);
|
|
+
|
|
+ /* link up, check the usb device control TX FIFO full or empty*/
|
|
+ ax88179_read_cmd(dev, 0x81, 0x8c, 0, 4, &tmp32, 1);
|
|
+
|
|
+ if (time_after(jiffies, jtimeout))
|
|
+ return 0;
|
|
+ }
|
|
+
|
|
+ mode = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN |
|
|
+ AX_MEDIUM_RXFLOW_CTRLEN;
|
|
+
|
|
+ ax88179_read_cmd(dev, AX_ACCESS_MAC, PHYSICAL_LINK_STATUS,
|
|
+ 1, 1, &link_sts, 0);
|
|
+ ax88179_read_cmd(dev, AX_ACCESS_PHY, AX88179_PHY_ID,
|
|
+ GMII_PHY_PHYSR, 2, &tmp16, 1);
|
|
+
|
|
+ if (!(tmp16 & GMII_PHY_PHYSR_LINK))
|
|
+ return 0;
|
|
+ else if (GMII_PHY_PHYSR_GIGA == (tmp16 & GMII_PHY_PHYSR_SMASK)) {
|
|
+ mode |= AX_MEDIUM_GIGAMODE | AX_MEDIUM_EN_125MHZ;
|
|
+ if (dev->net->mtu > 1500)
|
|
+ mode |= AX_MEDIUM_JUMBO_EN;
|
|
+
|
|
+ if (link_sts & AX_USB_SS)
|
|
+ memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5);
|
|
+ else if (link_sts & AX_USB_HS)
|
|
+ memcpy(tmp, &AX88179_BULKIN_SIZE[1], 5);
|
|
+ else
|
|
+ memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5);
|
|
+ } else if (GMII_PHY_PHYSR_100 == (tmp16 & GMII_PHY_PHYSR_SMASK)) {
|
|
+ mode |= AX_MEDIUM_PS; /* Bit 9 : PS */
|
|
+ if (link_sts & (AX_USB_SS | AX_USB_HS))
|
|
+ memcpy(tmp, &AX88179_BULKIN_SIZE[2], 5);
|
|
+ else
|
|
+ memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5);
|
|
+ } else
|
|
+ memcpy(tmp, &AX88179_BULKIN_SIZE[3], 5);
|
|
+
|
|
+ if (bsize != -1) {
|
|
+ if (bsize > 24)
|
|
+ bsize = 24;
|
|
+
|
|
+ else if (bsize == 0) {
|
|
+ tmp[1] = 0;
|
|
+ tmp[2] = 0;
|
|
+ }
|
|
+
|
|
+ tmp[3] = (u8)bsize;
|
|
+ }
|
|
+
|
|
+ if (ifg != -1) {
|
|
+ if (ifg > 255)
|
|
+ ifg = 255;
|
|
+ tmp[4] = (u8)ifg;
|
|
+ }
|
|
+
|
|
+ /* RX bulk configuration */
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp);
|
|
+
|
|
+ if (tmp16 & GMII_PHY_PHYSR_FULL)
|
|
+ mode |= AX_MEDIUM_FULL_DUPLEX; /* Bit 1 : FD */
|
|
+
|
|
+ dev->rx_urb_size = (1024 * (tmp[3] + 2));
|
|
+
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
|
|
+ netdev_info(dev->net, "Write medium type: 0x%04x\n", mode);
|
|
+#else
|
|
+ devinfo(dev, "Write medium type: 0x%04x\n", mode);
|
|
+#endif
|
|
+ /* Configure default medium type => giga */
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
|
|
+ 2, 2, &mode);
|
|
+ mii_check_media(&dev->mii, 1, 1);
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int ax88179_reset(struct usbnet *dev)
|
|
+{
|
|
+ void *buf = NULL;
|
|
+ u16 *tmp16 = NULL;
|
|
+ u8 *tmp = NULL;
|
|
+ struct ax88179_data *ax179_data = (struct ax88179_data *) dev->data;
|
|
+ buf = kmalloc(6, GFP_KERNEL);
|
|
+
|
|
+ if (!buf) {
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
|
|
+ netdev_err(dev->net, "Cannot allocate memory for buffer");
|
|
+#else
|
|
+ deverr(dev, "Cannot allocate memory for buffer");
|
|
+#endif
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ tmp16 = (u16 *)buf;
|
|
+ tmp = (u8 *)buf;
|
|
+
|
|
+ /* Power up ethernet PHY */
|
|
+ *tmp16 = 0;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
|
|
+ *tmp16 = AX_PHYPWR_RSTCTL_IPRL;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PHYPWR_RSTCTL, 2, 2, tmp16);
|
|
+ msleep(200);
|
|
+
|
|
+ *tmp = AX_CLK_SELECT_ACS | AX_CLK_SELECT_BCS;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_CLK_SELECT, 1, 1, tmp);
|
|
+ msleep(100);
|
|
+
|
|
+ /* Ethernet PHY Auto Detach*/
|
|
+ ax88179_AutoDetach(dev, 0);
|
|
+
|
|
+ /* Set the MAC address */
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_NODE_ID, ETH_ALEN,
|
|
+ ETH_ALEN, dev->net->dev_addr);
|
|
+
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
|
|
+ netdev_dbg(dev->net, "MAC [%02x-%02x-%02x-%02x-%02x-%02x]\n",
|
|
+ dev->net->dev_addr[0], dev->net->dev_addr[1],
|
|
+ dev->net->dev_addr[2], dev->net->dev_addr[3],
|
|
+ dev->net->dev_addr[4], dev->net->dev_addr[5]);
|
|
+#else
|
|
+ devdbg(dev, "MAC [%02x-%02x-%02x-%02x-%02x-%02x]\n",
|
|
+ dev->net->dev_addr[0], dev->net->dev_addr[1],
|
|
+ dev->net->dev_addr[2], dev->net->dev_addr[3],
|
|
+ dev->net->dev_addr[4], dev->net->dev_addr[5]);
|
|
+#endif
|
|
+
|
|
+ /* RX bulk configuration */
|
|
+ memcpy(tmp, &AX88179_BULKIN_SIZE[0], 5);
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_BULKIN_QCTRL, 5, 5, tmp);
|
|
+
|
|
+ dev->rx_urb_size = 1024 * 20;
|
|
+
|
|
+ tmp[0] = 0x34;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_LOW, 1, 1, tmp);
|
|
+
|
|
+ tmp[0] = 0x52;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_PAUSE_WATERLVL_HIGH,
|
|
+ 1, 1, tmp);
|
|
+
|
|
+ dev->net->features |= NETIF_F_IP_CSUM;
|
|
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)
|
|
+ dev->net->features |= NETIF_F_IPV6_CSUM;
|
|
+#endif
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
|
|
+ if (usb_device_no_sg_constraint(dev->udev))
|
|
+ dev->can_dma_sg = 1;
|
|
+ dev->net->features |= NETIF_F_SG | NETIF_F_TSO;
|
|
+#endif
|
|
+
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 39)
|
|
+ dev->net->hw_features |= NETIF_F_IP_CSUM;
|
|
+ dev->net->hw_features |= NETIF_F_IPV6_CSUM;
|
|
+ dev->net->hw_features |= NETIF_F_SG | NETIF_F_TSO;
|
|
+#endif
|
|
+
|
|
+ /* Enable checksum offload */
|
|
+ *tmp = AX_RXCOE_IP | AX_RXCOE_TCP | AX_RXCOE_UDP |
|
|
+ AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RXCOE_CTL, 1, 1, tmp);
|
|
+
|
|
+ *tmp = AX_TXCOE_IP | AX_TXCOE_TCP | AX_TXCOE_UDP |
|
|
+ AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_TXCOE_CTL, 1, 1, tmp);
|
|
+
|
|
+ ax179_data->checksum |= AX_RX_CHECKSUM | AX_TX_CHECKSUM;
|
|
+
|
|
+ /* Configure RX control register => start operation */
|
|
+ *tmp16 = AX_RX_CTL_DROPCRCERR | AX_RX_CTL_START | AX_RX_CTL_AP |
|
|
+ AX_RX_CTL_AMALL | AX_RX_CTL_AB;
|
|
+ if (NET_IP_ALIGN == 0)
|
|
+ *tmp16 |= AX_RX_CTL_IPE;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_RX_CTL, 2, 2, tmp16);
|
|
+
|
|
+ *tmp = AX_MONITOR_MODE_PMETYPE | AX_MONITOR_MODE_PMEPOL |
|
|
+ AX_MONITOR_MODE_RWMP;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MODE, 1, 1, tmp);
|
|
+
|
|
+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MONITOR_MODE, 1, 1, tmp, 0);
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
|
|
+ netdev_dbg(dev->net, "Monitor mode = 0x%02x\n", *tmp);
|
|
+#else
|
|
+ devdbg(dev, "Monitor mode = 0x%02x\n", *tmp);
|
|
+#endif
|
|
+
|
|
+ /* Configure default medium type => giga */
|
|
+ *tmp16 = AX_MEDIUM_RECEIVE_EN | AX_MEDIUM_TXFLOW_CTRLEN |
|
|
+ AX_MEDIUM_RXFLOW_CTRLEN | AX_MEDIUM_FULL_DUPLEX |
|
|
+ AX_MEDIUM_GIGAMODE;
|
|
+
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
|
|
+ 2, 2, tmp16);
|
|
+
|
|
+ ax88179_led_setting(dev);
|
|
+
|
|
+ ax88179_EEE_setting(dev);
|
|
+
|
|
+ ax88179_Gether_setting(dev);
|
|
+
|
|
+ /* Restart autoneg */
|
|
+ mii_nway_restart(&dev->mii);
|
|
+
|
|
+ netif_carrier_off(dev->net);
|
|
+
|
|
+ kfree(buf);
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 34)
|
|
+ netdev_dbg(dev->net, "mtu %d\n", dev->net->mtu);
|
|
+#else
|
|
+ devdbg(dev, "mtu %d\n", dev->net->mtu);
|
|
+#endif
|
|
+
|
|
+ return 0;
|
|
+
|
|
+}
|
|
+
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
|
|
+static int ax88179_stop(struct usbnet *dev)
|
|
+{
|
|
+ u16 tmp16 = 0;
|
|
+
|
|
+ ax88179_read_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
|
|
+ 2, 2, &tmp16, 1);
|
|
+ tmp16 &= ~AX_MEDIUM_RECEIVE_EN;
|
|
+ ax88179_write_cmd(dev, AX_ACCESS_MAC, AX_MEDIUM_STATUS_MODE,
|
|
+ 2, 2, &tmp16);
|
|
+ return 0;
|
|
+}
|
|
+#endif
|
|
+
|
|
+static const struct driver_info ax88179_info = {
|
|
+ .description = "ASIX AX88179 USB 3.0 Gigabit Ethernet",
|
|
+ .bind = ax88179_bind,
|
|
+ .unbind = ax88179_unbind,
|
|
+ .status = ax88179_status,
|
|
+ .link_reset = ax88179_link_reset,
|
|
+ .reset = ax88179_reset,
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
|
|
+ .stop = ax88179_stop,
|
|
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS,
|
|
+#else
|
|
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
|
|
+#endif
|
|
+ .rx_fixup = ax88179_rx_fixup,
|
|
+ .tx_fixup = ax88179_tx_fixup,
|
|
+};
|
|
+
|
|
+
|
|
+static const struct driver_info ax88178a_info = {
|
|
+ .description = "ASIX AX88178A USB 2.0 Gigabit Ethernet",
|
|
+ .bind = ax88179_bind,
|
|
+ .unbind = ax88179_unbind,
|
|
+ .status = ax88179_status,
|
|
+ .link_reset = ax88179_link_reset,
|
|
+ .reset = ax88179_reset,
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
|
|
+ .stop = ax88179_stop,
|
|
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS,
|
|
+#else
|
|
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
|
|
+#endif
|
|
+ .rx_fixup = ax88179_rx_fixup,
|
|
+ .tx_fixup = ax88179_tx_fixup,
|
|
+};
|
|
+
|
|
+static const struct driver_info sitecom_info = {
|
|
+ .description = "Sitecom USB 3.0 to Gigabit Adapter",
|
|
+ .bind = ax88179_bind,
|
|
+ .unbind = ax88179_unbind,
|
|
+ .status = ax88179_status,
|
|
+ .link_reset = ax88179_link_reset,
|
|
+ .reset = ax88179_reset,
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
|
|
+ .stop = ax88179_stop,
|
|
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS,
|
|
+#else
|
|
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
|
|
+#endif
|
|
+ .rx_fixup = ax88179_rx_fixup,
|
|
+ .tx_fixup = ax88179_tx_fixup,
|
|
+};
|
|
+
|
|
+static const struct driver_info lenovo_info = {
|
|
+ .description = "ThinkPad OneLinkDock USB GigaLAN",
|
|
+ .bind = ax88179_bind,
|
|
+ .unbind = ax88179_unbind,
|
|
+ .status = ax88179_status,
|
|
+ .link_reset = ax88179_link_reset,
|
|
+ .reset = ax88179_reset,
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
|
|
+ .stop = ax88179_stop,
|
|
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS,
|
|
+#else
|
|
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
|
|
+#endif
|
|
+ .rx_fixup = ax88179_rx_fixup,
|
|
+ .tx_fixup = ax88179_tx_fixup,
|
|
+};
|
|
+
|
|
+static const struct driver_info toshiba_info = {
|
|
+ .description = "Toshiba USB 3.0 to Gigabit LAN Adapter",
|
|
+ .bind = ax88179_bind,
|
|
+ .unbind = ax88179_unbind,
|
|
+ .status = ax88179_status,
|
|
+ .link_reset = ax88179_link_reset,
|
|
+ .reset = ax88179_reset,
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
|
|
+ .stop = ax88179_stop,
|
|
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS,
|
|
+#else
|
|
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
|
|
+#endif
|
|
+ .rx_fixup = ax88179_rx_fixup,
|
|
+ .tx_fixup = ax88179_tx_fixup,
|
|
+};
|
|
+
|
|
+static const struct driver_info samsung_info = {
|
|
+ .description = "Samsung USB Ethernet Adapter",
|
|
+ .bind = ax88179_bind,
|
|
+ .unbind = ax88179_unbind,
|
|
+ .status = ax88179_status,
|
|
+ .link_reset = ax88179_link_reset,
|
|
+ .reset = ax88179_reset,
|
|
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 32)
|
|
+ .stop = ax88179_stop,
|
|
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_AVOID_UNLINK_URBS,
|
|
+#else
|
|
+ .flags = FLAG_ETHER | FLAG_FRAMING_AX,
|
|
+#endif
|
|
+ .rx_fixup = ax88179_rx_fixup,
|
|
+ .tx_fixup = ax88179_tx_fixup,
|
|
+};
|
|
+
|
|
+static const struct usb_device_id products[] = {
|
|
+{
|
|
+ /* ASIX AX88179 10/100/1000 */
|
|
+ USB_DEVICE(0x0b95, 0x1790),
|
|
+ .driver_info = (unsigned long) &ax88179_info,
|
|
+}, {
|
|
+ /* ASIX AX88178A 10/100/1000 */
|
|
+ USB_DEVICE(0x0b95, 0x178a),
|
|
+ .driver_info = (unsigned long) &ax88178a_info,
|
|
+}, {
|
|
+ /* Sitecom USB 3.0 to Gigabit Adapter */
|
|
+ USB_DEVICE(0x0df6, 0x0072),
|
|
+ .driver_info = (unsigned long) &sitecom_info,
|
|
+}, {
|
|
+ /* ThinkPad OneLinkDock USB GigaLAN */
|
|
+ USB_DEVICE(0x17ef, 0x304b),
|
|
+ .driver_info = (unsigned long) &lenovo_info,
|
|
+}, {
|
|
+ /* Toshiba USB3.0 to Gigabit LAN Adapter */
|
|
+ USB_DEVICE(0x0930, 0x0a13),
|
|
+ .driver_info = (unsigned long) &toshiba_info,
|
|
+}, {
|
|
+ /* Samsung USB Ethernet Adapter */
|
|
+ USB_DEVICE(0x04e8, 0xa100),
|
|
+ .driver_info = (unsigned long) &samsung_info,
|
|
+},
|
|
+ { }, /* END */
|
|
+};
|
|
+MODULE_DEVICE_TABLE(usb, products);
|
|
+
|
|
+static struct usb_driver asix_driver = {
|
|
+ .name = "ax88179_178a",
|
|
+ .id_table = products,
|
|
+ .probe = usbnet_probe,
|
|
+ .suspend = ax88179_suspend,
|
|
+ .resume = ax88179_resume,
|
|
+ .disconnect = usbnet_disconnect,
|
|
+};
|
|
+
|
|
+
|
|
+static int __init asix_init(void)
|
|
+{
|
|
+ return usb_register(&asix_driver);
|
|
+}
|
|
+module_init(asix_init);
|
|
+
|
|
+static void __exit asix_exit(void)
|
|
+{
|
|
+ usb_deregister(&asix_driver);
|
|
+}
|
|
+module_exit(asix_exit);
|
|
+
|
|
+MODULE_AUTHOR("David Hollis");
|
|
+MODULE_DESCRIPTION("ASIX AX88179_178A based USB 2.0/3.0 Gigabit Ethernet Devices");
|
|
+MODULE_LICENSE("GPL");
|
|
+
|
|
diff --git a/drivers/net/usb/ax88179_178a.h b/drivers/net/usb/ax88179_178a.h
|
|
new file mode 100644
|
|
index 0000000..cbe4e9f
|
|
--- /dev/null
|
|
+++ b/drivers/net/usb/ax88179_178a.h
|
|
@@ -0,0 +1,365 @@
|
|
+#ifndef __LINUX_USBNET_ASIX_H
|
|
+#define __LINUX_USBNET_ASIX_H
|
|
+
|
|
+//#define RX_SKB_COPY
|
|
+
|
|
+#define AX88179_PHY_ID 0x03
|
|
+#define AX_MCAST_FILTER_SIZE 8
|
|
+#define AX_MAX_MCAST 64
|
|
+#define AX_EEPROM_LEN 0x40
|
|
+#define AX_RX_CHECKSUM 1
|
|
+#define AX_TX_CHECKSUM 2
|
|
+
|
|
+#define AX_BULKIN_24K 0x18; /* 24k */
|
|
+
|
|
+#define AX_ACCESS_MAC 0x01
|
|
+#define AX_ACCESS_PHY 0x02
|
|
+#define AX_ACCESS_WAKEUP 0x03
|
|
+#define AX_ACCESS_EEPROM 0x04
|
|
+#define AX_ACCESS_EFUSE 0x05
|
|
+#define AX_RELOAD_EEPROM_EFUSE 0x06
|
|
+#define AX_WRITE_EFUSE_EN 0x09
|
|
+#define AX_WRITE_EFUSE_DIS 0x0A
|
|
+#define AX_ACCESS_MFAB 0x10
|
|
+
|
|
+#define PHYSICAL_LINK_STATUS 0x02
|
|
+ #define AX_USB_SS 0x04
|
|
+ #define AX_USB_HS 0x02
|
|
+ #define AX_USB_FS 0x01
|
|
+
|
|
+#define GENERAL_STATUS 0x03
|
|
+/* Check AX88179 version. UA1:Bit2 = 0, UA2:Bit2 = 1 */
|
|
+ #define AX_SECLD 0x04
|
|
+
|
|
+
|
|
+
|
|
+#define AX_SROM_ADDR 0x07
|
|
+#define AX_SROM_CMD 0x0a
|
|
+ #define EEP_RD 0x04 /* EEprom read command */
|
|
+ #define EEP_WR 0x08 /* EEprom write command */
|
|
+ #define EEP_BUSY 0x10 /* EEprom access module busy */
|
|
+
|
|
+
|
|
+#define AX_SROM_DATA_LOW 0x08
|
|
+#define AX_SROM_DATA_HIGH 0x09
|
|
+
|
|
+#define AX_RX_CTL 0x0b
|
|
+ #define AX_RX_CTL_DROPCRCERR 0x0100 /* Drop CRC error packet */
|
|
+ #define AX_RX_CTL_IPE 0x0200 /* Enable IP header in receive buffer aligned on 32-bit aligment */
|
|
+ #define AX_RX_CTL_TXPADCRC 0x0400 /* checksum value in rx header 3 */
|
|
+ #define AX_RX_CTL_START 0x0080 /* Ethernet MAC start */
|
|
+ #define AX_RX_CTL_AP 0x0020 /* Accept physcial address from Multicast array */
|
|
+ #define AX_RX_CTL_AM 0x0010 /* Accetp Brocadcast frames*/
|
|
+ #define AX_RX_CTL_AB 0x0008 /* HW auto-added 8-bytes data when meet USB bulk in transfer boundary (1024/512/64)*/
|
|
+ #define AX_RX_CTL_HA8B 0x0004
|
|
+ #define AX_RX_CTL_AMALL 0x0002 /* Accetp all multicast frames */
|
|
+ #define AX_RX_CTL_PRO 0x0001 /* Promiscuous Mode */
|
|
+ #define AX_RX_CTL_STOP 0x0000 /* Stop MAC */
|
|
+
|
|
+#define AX_NODE_ID 0x10
|
|
+#define AX_MULTI_FILTER_ARRY 0x16
|
|
+
|
|
+#define AX_MEDIUM_STATUS_MODE 0x22
|
|
+ #define AX_MEDIUM_GIGAMODE 0x01
|
|
+ #define AX_MEDIUM_FULL_DUPLEX 0x02
|
|
+// #define AX_MEDIUM_ALWAYS_ONE 0x04
|
|
+ #define AX_MEDIUM_EN_125MHZ 0x08
|
|
+ #define AX_MEDIUM_RXFLOW_CTRLEN 0x10
|
|
+ #define AX_MEDIUM_TXFLOW_CTRLEN 0x20
|
|
+ #define AX_MEDIUM_RECEIVE_EN 0x100
|
|
+ #define AX_MEDIUM_PS 0x200
|
|
+ #define AX_MEDIUM_JUMBO_EN 0x8040
|
|
+
|
|
+#define AX_MONITOR_MODE 0x24
|
|
+ #define AX_MONITOR_MODE_RWLC 0x02
|
|
+ #define AX_MONITOR_MODE_RWMP 0x04
|
|
+ #define AX_MONITOR_MODE_RWWF 0x08
|
|
+ #define AX_MONITOR_MODE_RW_FLAG 0x10
|
|
+ #define AX_MONITOR_MODE_PMEPOL 0x20
|
|
+ #define AX_MONITOR_MODE_PMETYPE 0x40
|
|
+
|
|
+#define AX_GPIO_CTRL 0x25
|
|
+ #define AX_GPIO_CTRL_GPIO3EN 0x80
|
|
+ #define AX_GPIO_CTRL_GPIO2EN 0x40
|
|
+ #define AX_GPIO_CTRL_GPIO1EN 0x20
|
|
+
|
|
+#define AX_PHYPWR_RSTCTL 0x26
|
|
+ #define AX_PHYPWR_RSTCTL_BZ 0x0010
|
|
+ #define AX_PHYPWR_RSTCTL_IPRL 0x0020
|
|
+ #define AX_PHYPWR_RSTCTL_AUTODETACH 0x1000
|
|
+
|
|
+#define AX_RX_BULKIN_QCTRL 0x2e
|
|
+ #define AX_RX_BULKIN_QCTRL_TIME 0x01
|
|
+ #define AX_RX_BULKIN_QCTRL_IFG 0x02
|
|
+ #define AX_RX_BULKIN_QCTRL_SIZE 0x04
|
|
+
|
|
+#define AX_RX_BULKIN_QTIMR_LOW 0x2f
|
|
+#define AX_RX_BULKIN_QTIMR_HIGH 0x30
|
|
+#define AX_RX_BULKIN_QSIZE 0x31
|
|
+#define AX_RX_BULKIN_QIFG 0x32
|
|
+
|
|
+#define AX_CLK_SELECT 0x33
|
|
+ #define AX_CLK_SELECT_BCS 0x01
|
|
+ #define AX_CLK_SELECT_ACS 0x02
|
|
+ #define AX_CLK_SELECT_ACSREQ 0x10
|
|
+ #define AX_CLK_SELECT_ULR 0x08
|
|
+
|
|
+#define AX_RXCOE_CTL 0x34
|
|
+ #define AX_RXCOE_IP 0x01
|
|
+ #define AX_RXCOE_TCP 0x02
|
|
+ #define AX_RXCOE_UDP 0x04
|
|
+ #define AX_RXCOE_ICMP 0x08
|
|
+ #define AX_RXCOE_IGMP 0x10
|
|
+ #define AX_RXCOE_TCPV6 0x20
|
|
+ #define AX_RXCOE_UDPV6 0x40
|
|
+ #define AX_RXCOE_ICMV6 0x80
|
|
+
|
|
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)
|
|
+ #define AX_RXCOE_DEF_CSUM (AX_RXCOE_IP | AX_RXCOE_TCP | \
|
|
+ AX_RXCOE_UDP | AX_RXCOE_ICMV6 | \
|
|
+ AX_RXCOE_TCPV6 | AX_RXCOE_UDPV6)
|
|
+#else
|
|
+ #define AX_RXCOE_DEF_CSUM (AX_RXCOE_IP | AX_RXCOE_TCP | \
|
|
+ AX_RXCOE_UDP)
|
|
+#endif
|
|
+
|
|
+#define AX_TXCOE_CTL 0x35
|
|
+ #define AX_TXCOE_IP 0x01
|
|
+ #define AX_TXCOE_TCP 0x02
|
|
+ #define AX_TXCOE_UDP 0x04
|
|
+ #define AX_TXCOE_ICMP 0x08
|
|
+ #define AX_TXCOE_IGMP 0x10
|
|
+ #define AX_TXCOE_TCPV6 0x20
|
|
+ #define AX_TXCOE_UDPV6 0x40
|
|
+ #define AX_TXCOE_ICMV6 0x80
|
|
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22)
|
|
+ #define AX_TXCOE_DEF_CSUM (AX_TXCOE_TCP | AX_TXCOE_UDP | \
|
|
+ AX_TXCOE_TCPV6 | AX_TXCOE_UDPV6)
|
|
+#else
|
|
+ #define AX_TXCOE_DEF_CSUM (AX_TXCOE_TCP | AX_TXCOE_UDP)
|
|
+#endif
|
|
+
|
|
+#define AX_PAUSE_WATERLVL_HIGH 0x54
|
|
+#define AX_PAUSE_WATERLVL_LOW 0x55
|
|
+
|
|
+
|
|
+#define AX_EEP_EFUSE_CORRECT 0x00
|
|
+#define AX88179_EEPROM_MAGIC 0x17900b95
|
|
+
|
|
+
|
|
+/*****************************************************************************/
|
|
+/* GMII register definitions */
|
|
+#define GMII_PHY_CONTROL 0x00 /* control reg */
|
|
+ /* Bit definitions: GMII Control */
|
|
+ #define GMII_CONTROL_RESET 0x8000 /* reset bit in control reg */
|
|
+ #define GMII_CONTROL_LOOPBACK 0x4000 /* loopback bit in control reg */
|
|
+ #define GMII_CONTROL_10MB 0x0000 /* 10 Mbit */
|
|
+ #define GMII_CONTROL_100MB 0x2000 /* 100Mbit */
|
|
+ #define GMII_CONTROL_1000MB 0x0040 /* 1000Mbit */
|
|
+ #define GMII_CONTROL_SPEED_BITS 0x2040 /* speed bit mask */
|
|
+ #define GMII_CONTROL_ENABLE_AUTO 0x1000 /* autonegotiate enable */
|
|
+ #define GMII_CONTROL_POWER_DOWN 0x0800
|
|
+ #define GMII_CONTROL_ISOLATE 0x0400 /* islolate bit */
|
|
+ #define GMII_CONTROL_START_AUTO 0x0200 /* restart autonegotiate */
|
|
+ #define GMII_CONTROL_FULL_DUPLEX 0x0100
|
|
+
|
|
+#define GMII_PHY_STATUS 0x01 /* status reg */
|
|
+ /* Bit definitions: GMII Status */
|
|
+ #define GMII_STATUS_100MB_MASK 0xE000 /* any of these indicate 100 Mbit */
|
|
+ #define GMII_STATUS_10MB_MASK 0x1800 /* either of these indicate 10 Mbit */
|
|
+ #define GMII_STATUS_AUTO_DONE 0x0020 /* auto negotiation complete */
|
|
+ #define GMII_STATUS_AUTO 0x0008 /* auto negotiation is available */
|
|
+ #define GMII_STATUS_LINK_UP 0x0004 /* link status bit */
|
|
+ #define GMII_STATUS_EXTENDED 0x0001 /* extended regs exist */
|
|
+ #define GMII_STATUS_100T4 0x8000 /* capable of 100BT4 */
|
|
+ #define GMII_STATUS_100TXFD 0x4000 /* capable of 100BTX full duplex */
|
|
+ #define GMII_STATUS_100TX 0x2000 /* capable of 100BTX */
|
|
+ #define GMII_STATUS_10TFD 0x1000 /* capable of 10BT full duplex */
|
|
+ #define GMII_STATUS_10T 0x0800 /* capable of 10BT */
|
|
+
|
|
+#define GMII_PHY_OUI 0x02 /* most of the OUI bits */
|
|
+#define GMII_PHY_MODEL 0x03 /* model/rev bits, and rest of OUI */
|
|
+#define GMII_PHY_ANAR 0x04 /* AN advertisement reg */
|
|
+ /* Bit definitions: Auto-Negotiation Advertisement */
|
|
+ #define GMII_ANAR_ASYM_PAUSE 0x0800 /* support asymetric pause */
|
|
+ #define GMII_ANAR_PAUSE 0x0400 /* support pause packets */
|
|
+ #define GMII_ANAR_100T4 0x0200 /* support 100BT4 */
|
|
+ #define GMII_ANAR_100TXFD 0x0100 /* support 100BTX full duplex */
|
|
+ #define GMII_ANAR_100TX 0x0080 /* support 100BTX half duplex */
|
|
+ #define GMII_ANAR_10TFD 0x0040 /* support 10BT full duplex */
|
|
+ #define GMII_ANAR_10T 0x0020 /* support 10BT half duplex */
|
|
+ #define GMII_SELECTOR_FIELD 0x001F /* selector field. */
|
|
+
|
|
+#define GMII_PHY_ANLPAR 0x05 /* AN Link Partner */
|
|
+ /* Bit definitions: Auto-Negotiation Link Partner Ability */
|
|
+ #define GMII_ANLPAR_100T4 0x0200 /* support 100BT4 */
|
|
+ #define GMII_ANLPAR_100TXFD 0x0100 /* support 100BTX full duplex */
|
|
+ #define GMII_ANLPAR_100TX 0x0080 /* support 100BTX half duplex */
|
|
+ #define GMII_ANLPAR_10TFD 0x0040 /* support 10BT full duplex */
|
|
+ #define GMII_ANLPAR_10T 0x0020 /* support 10BT half duplex */
|
|
+ #define GMII_ANLPAR_PAUSE 0x0400 /* support pause packets */
|
|
+ #define GMII_ANLPAR_ASYM_PAUSE 0x0800 /* support asymetric pause */
|
|
+ #define GMII_ANLPAR_ACK 0x4000 /* means LCB was successfully rx'd */
|
|
+ #define GMII_SELECTOR_8023 0x0001;
|
|
+
|
|
+#define GMII_PHY_ANER 0x06 /* AN expansion reg */
|
|
+#define GMII_PHY_1000BT_CONTROL 0x09 /* control reg for 1000BT */
|
|
+#define GMII_PHY_1000BT_STATUS 0x0A /* status reg for 1000BT */
|
|
+
|
|
+#define GMII_PHY_MACR 0x0D
|
|
+#define GMII_PHY_MAADR 0x0E
|
|
+
|
|
+#define GMII_PHY_PHYSR 0x11 /* PHY specific status register */
|
|
+ #define GMII_PHY_PHYSR_SMASK 0xc000
|
|
+ #define GMII_PHY_PHYSR_GIGA 0x8000
|
|
+ #define GMII_PHY_PHYSR_100 0x4000
|
|
+ #define GMII_PHY_PHYSR_FULL 0x2000
|
|
+ #define GMII_PHY_PHYSR_LINK 0x400
|
|
+
|
|
+/* Bit definitions: 1000BaseT AUX Control */
|
|
+#define GMII_1000_AUX_CTRL_MASTER_SLAVE 0x1000
|
|
+#define GMII_1000_AUX_CTRL_FD_CAPABLE 0x0200 /* full duplex capable */
|
|
+#define GMII_1000_AUX_CTRL_HD_CAPABLE 0x0100 /* half duplex capable */
|
|
+
|
|
+/* Bit definitions: 1000BaseT AUX Status */
|
|
+#define GMII_1000_AUX_STATUS_FD_CAPABLE 0x0800 /* full duplex capable */
|
|
+#define GMII_1000_AUX_STATUS_HD_CAPABLE 0x0400 /* half duplex capable */
|
|
+
|
|
+/*Cicada MII Registers */
|
|
+#define GMII_AUX_CTRL_STATUS 0x1C
|
|
+#define GMII_AUX_ANEG_CPLT 0x8000
|
|
+#define GMII_AUX_FDX 0x0020
|
|
+#define GMII_AUX_SPEED_1000 0x0010
|
|
+#define GMII_AUX_SPEED_100 0x0008
|
|
+
|
|
+#define GMII_LED_ACTIVE 0x1a
|
|
+ #define GMII_LED_ACTIVE_MASK 0xff8f
|
|
+ #define GMII_LED0_ACTIVE (1 << 4)
|
|
+ #define GMII_LED1_ACTIVE (1 << 5)
|
|
+ #define GMII_LED2_ACTIVE (1 << 6)
|
|
+
|
|
+#define GMII_LED_LINK 0x1c
|
|
+ #define GMII_LED_LINK_MASK 0xf888
|
|
+ #define GMII_LED0_LINK_10 (1 << 0)
|
|
+ #define GMII_LED0_LINK_100 (1 << 1)
|
|
+ #define GMII_LED0_LINK_1000 (1 << 2)
|
|
+ #define GMII_LED1_LINK_10 (1 << 4)
|
|
+ #define GMII_LED1_LINK_100 (1 << 5)
|
|
+ #define GMII_LED1_LINK_1000 (1 << 6)
|
|
+ #define GMII_LED2_LINK_10 (1 << 8)
|
|
+ #define GMII_LED2_LINK_100 (1 << 9)
|
|
+ #define GMII_LED2_LINK_1000 (1 << 10)
|
|
+
|
|
+ #define LED_VALID (1 << 15) /* UA2 LED Setting */
|
|
+
|
|
+ #define LED0_ACTIVE (1 << 0)
|
|
+ #define LED0_LINK_10 (1 << 1)
|
|
+ #define LED0_LINK_100 (1 << 2)
|
|
+ #define LED0_LINK_1000 (1 << 3)
|
|
+ #define LED0_FD (1 << 4)
|
|
+ #define LED0_USB3_MASK 0x001f
|
|
+
|
|
+ #define LED1_ACTIVE (1 << 5)
|
|
+ #define LED1_LINK_10 (1 << 6)
|
|
+ #define LED1_LINK_100 (1 << 7)
|
|
+ #define LED1_LINK_1000 (1 << 8)
|
|
+ #define LED1_FD (1 << 9)
|
|
+ #define LED1_USB3_MASK 0x03e0
|
|
+
|
|
+ #define LED2_ACTIVE (1 << 10)
|
|
+ #define LED2_LINK_1000 (1 << 13)
|
|
+ #define LED2_LINK_100 (1 << 12)
|
|
+ #define LED2_LINK_10 (1 << 11)
|
|
+ #define LED2_FD (1 << 14)
|
|
+ #define LED2_USB3_MASK 0x7c00
|
|
+
|
|
+#define GMII_PHYPAGE 0x1e
|
|
+
|
|
+#define GMII_PHY_PAGE_SELECT 0x1f
|
|
+ #define GMII_PHY_PAGE_SELECT_EXT 0x0007
|
|
+ #define GMII_PHY_PAGE_SELECT_PAGE0 0X0000
|
|
+ #define GMII_PHY_PAGE_SELECT_PAGE1 0X0001
|
|
+ #define GMII_PHY_PAGE_SELECT_PAGE2 0X0002
|
|
+ #define GMII_PHY_PAGE_SELECT_PAGE3 0X0003
|
|
+ #define GMII_PHY_PAGE_SELECT_PAGE4 0X0004
|
|
+ #define GMII_PHY_PAGE_SELECT_PAGE5 0X0005
|
|
+ #define GMII_PHY_PAGE_SELECT_PAGE6 0X0006
|
|
+
|
|
+/******************************************************************************/
|
|
+
|
|
+struct ax88179_data {
|
|
+ u16 rxctl;
|
|
+ u8 checksum;
|
|
+} __attribute__ ((packed));
|
|
+
|
|
+struct ax88179_async_handle {
|
|
+ struct usb_ctrlrequest *req;
|
|
+ u8 m_filter[8];
|
|
+ u16 rxctl;
|
|
+} __attribute__ ((packed));
|
|
+
|
|
+struct ax88179_int_data {
|
|
+ __le16 res1;
|
|
+#define AX_INT_PPLS_LINK (1 << 0)
|
|
+#define AX_INT_SPLS_LINK (1 << 1)
|
|
+#define AX_INT_CABOFF_UNPLUG (1 << 7)
|
|
+ u8 link;
|
|
+ __le16 res2;
|
|
+ u8 status;
|
|
+ __le16 res3;
|
|
+} __attribute__ ((packed));
|
|
+
|
|
+#define AX_RXHDR_L4_ERR (1 << 8)
|
|
+#define AX_RXHDR_L3_ERR (1 << 9)
|
|
+
|
|
+
|
|
+#define AX_RXHDR_L4_TYPE_ICMP 2
|
|
+#define AX_RXHDR_L4_TYPE_IGMP 3
|
|
+#define AX_RXHDR_L4_TYPE_TCMPV6 5
|
|
+
|
|
+#define AX_RXHDR_L3_TYPE_IP 1
|
|
+#define AX_RXHDR_L3_TYPE_IPV6 2
|
|
+
|
|
+#define AX_RXHDR_L4_TYPE_MASK 0x1c
|
|
+#define AX_RXHDR_L4_TYPE_UDP 4
|
|
+#define AX_RXHDR_L4_TYPE_TCP 16
|
|
+#define AX_RXHDR_L3CSUM_ERR 2
|
|
+#define AX_RXHDR_L4CSUM_ERR 1
|
|
+#define AX_RXHDR_CRC_ERR 0x20000000
|
|
+#define AX_RXHDR_MII_ERR 0x40000000
|
|
+#define AX_RXHDR_DROP_ERR 0x80000000
|
|
+#if 0
|
|
+struct ax88179_rx_pkt_header {
|
|
+
|
|
+ u8 l4_csum_err:1,
|
|
+ l3_csum_err:1,
|
|
+ l4_type:3,
|
|
+ l3_type:2,
|
|
+ ce:1;
|
|
+
|
|
+ u8 vlan_ind:3,
|
|
+ rx_ok:1,
|
|
+ pri:3,
|
|
+ bmc:1;
|
|
+
|
|
+ u16 len:13,
|
|
+ crc:1,
|
|
+ mii:1,
|
|
+ drop:1;
|
|
+
|
|
+} __attribute__ ((packed));
|
|
+#endif
|
|
+static struct {unsigned char ctrl, timer_l, timer_h, size, ifg; }
|
|
+AX88179_BULKIN_SIZE[] = {
|
|
+ {7, 0x4f, 0, 0x12, 0xff},
|
|
+ {7, 0x20, 3, 0x16, 0xff},
|
|
+ {7, 0xae, 7, 0x18, 0xff},
|
|
+ {7, 0xcc, 0x4c, 0x18, 8},
|
|
+};
|
|
+
|
|
+static int ax88179_reset(struct usbnet *dev);
|
|
+static int ax88179_link_reset(struct usbnet *dev);
|
|
+static int ax88179_AutoDetach(struct usbnet *dev, int in_pm);
|
|
+
|
|
+#endif /* __LINUX_USBNET_ASIX_H */
|
|
+
|
|
--
|
|
1.9.1
|
|
|