diff options
Diffstat (limited to 'drivers/net/usb')
39 files changed, 2024 insertions, 301 deletions
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig index 85e4a01670f0..7e7269fd3707 100644 --- a/drivers/net/usb/Kconfig +++ b/drivers/net/usb/Kconfig @@ -92,11 +92,12 @@ config USB_RTL8150 module will be called rtl8150. config USB_RTL8152 - tristate "Realtek RTL8152 Based USB 2.0 Ethernet Adapters" + tristate "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" select MII help This option adds support for Realtek RTL8152 based USB 2.0 - 10/100 Ethernet adapters. + 10/100 Ethernet adapters and RTL8153 based USB 3.0 10/100/1000 + Ethernet adapters. To compile this driver as a module, choose M here: the module will be called r8152. @@ -276,12 +277,12 @@ config USB_NET_CDC_MBIM module will be called cdc_mbim. config USB_NET_DM9601 - tristate "Davicom DM9601 based USB 1.1 10/100 ethernet devices" + tristate "Davicom DM96xx based USB 10/100 ethernet devices" depends on USB_USBNET select CRC32 help - This option adds support for Davicom DM9601 based USB 1.1 - 10/100 Ethernet adapters. + This option adds support for Davicom DM9601/DM9620/DM9621A + based USB 10/100 Ethernet adapters. config USB_NET_SR9700 tristate "CoreChip-sz SR9700 based USB 1.1 10/100 ethernet devices" @@ -291,6 +292,21 @@ config USB_NET_SR9700 This option adds support for CoreChip-sz SR9700 based USB 1.1 10/100 Ethernet adapters. +config USB_NET_SR9800 + tristate "CoreChip-sz SR9800 based USB 2.0 10/100 ethernet devices" + depends on USB_USBNET + select CRC32 + ---help--- + Say Y if you want to use one of the following 100Mbps USB Ethernet + device based on the CoreChip-sz SR9800 chip. + + This driver makes the adapter appear as a normal Ethernet interface, + typically on eth0, if it is the only ethernet device, or perhaps on + eth1, if you have a PCI or ISA ethernet card installed. + + To compile this driver as a module, choose M here: the + module will be called sr9800. + config USB_NET_SMSC75XX tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices" depends on USB_USBNET diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile index b17b5e88bbaf..433f0a00c683 100644 --- a/drivers/net/usb/Makefile +++ b/drivers/net/usb/Makefile @@ -15,6 +15,7 @@ obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o r815x.o obj-$(CONFIG_USB_NET_CDC_EEM) += cdc_eem.o obj-$(CONFIG_USB_NET_DM9601) += dm9601.o obj-$(CONFIG_USB_NET_SR9700) += sr9700.o +obj-$(CONFIG_USB_NET_SR9800) += sr9800.o obj-$(CONFIG_USB_NET_SMSC75XX) += smsc75xx.o obj-$(CONFIG_USB_NET_SMSC95XX) += smsc95xx.o obj-$(CONFIG_USB_NET_GL620A) += gl620a.o diff --git a/drivers/net/usb/asix.h b/drivers/net/usb/asix.h index bdaa12d07a12..5d049d00c2d7 100644 --- a/drivers/net/usb/asix.h +++ b/drivers/net/usb/asix.h @@ -16,8 +16,7 @@ * 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 + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #ifndef _ASIX_H @@ -28,7 +27,6 @@ #include <linux/module.h> #include <linux/kmod.h> -#include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> diff --git a/drivers/net/usb/asix_common.c b/drivers/net/usb/asix_common.c index 577c72d5f369..5c55f11572ba 100644 --- a/drivers/net/usb/asix_common.c +++ b/drivers/net/usb/asix_common.c @@ -16,8 +16,7 @@ * 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 + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include "asix.h" diff --git a/drivers/net/usb/asix_devices.c b/drivers/net/usb/asix_devices.c index 386a3df53678..5d194093f3e1 100644 --- a/drivers/net/usb/asix_devices.c +++ b/drivers/net/usb/asix_devices.c @@ -16,8 +16,7 @@ * 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 + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include "asix.h" @@ -918,7 +917,8 @@ static const struct driver_info ax88178_info = { .status = asix_status, .link_reset = ax88178_link_reset, .reset = ax88178_reset, - .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR, + .flags = FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | + FLAG_MULTI_PACKET, .rx_fixup = asix_rx_fixup_common, .tx_fixup = asix_tx_fixup, }; diff --git a/drivers/net/usb/ax88172a.c b/drivers/net/usb/ax88172a.c index 723b3879ecc2..5f18fcb8dcc7 100644 --- a/drivers/net/usb/ax88172a.c +++ b/drivers/net/usb/ax88172a.c @@ -21,8 +21,7 @@ * 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 + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include "asix.h" diff --git a/drivers/net/usb/ax88179_178a.c b/drivers/net/usb/ax88179_178a.c index 8e8d0fcd4979..955df81a4358 100644 --- a/drivers/net/usb/ax88179_178a.c +++ b/drivers/net/usb/ax88179_178a.c @@ -14,8 +14,7 @@ * 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. + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/module.h> @@ -1119,6 +1118,10 @@ static int ax88179_rx_fixup(struct usbnet *dev, struct sk_buff *skb) u16 hdr_off; u32 *pkt_hdr; + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + skb_trim(skb, skb->len - 4); memcpy(&rx_hdr, skb_tail_pointer(skb), 4); le32_to_cpus(&rx_hdr); diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index df507e6dbb9c..630caf48f63a 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -24,15 +24,13 @@ * 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 + * along with this program; if not, see <http://www.gnu.org/licenses/>. * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail: * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ -#include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> #include <linux/string.h> diff --git a/drivers/net/usb/cdc_eem.c b/drivers/net/usb/cdc_eem.c index 08d55b6bf272..f7180f8db39e 100644 --- a/drivers/net/usb/cdc_eem.c +++ b/drivers/net/usb/cdc_eem.c @@ -14,12 +14,10 @@ * 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 + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/module.h> -#include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ctype.h> diff --git a/drivers/net/usb/cdc_ether.c b/drivers/net/usb/cdc_ether.c index 2023f3ea891e..42e176912c8e 100644 --- a/drivers/net/usb/cdc_ether.c +++ b/drivers/net/usb/cdc_ether.c @@ -14,15 +14,13 @@ * 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 + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ // #define DEBUG // error path messages, extra info // #define VERBOSE // more; success messages #include <linux/module.h> -#include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> @@ -487,6 +485,7 @@ static const struct driver_info wwan_info = { #define ZTE_VENDOR_ID 0x19D2 #define DELL_VENDOR_ID 0x413C #define REALTEK_VENDOR_ID 0x0bda +#define SAMSUNG_VENDOR_ID 0x04e8 static const struct usb_device_id products[] = { /* BLACKLIST !! diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c index e15ec2b12035..dbff290ed0e4 100644 --- a/drivers/net/usb/cdc_ncm.c +++ b/drivers/net/usb/cdc_ncm.c @@ -39,7 +39,6 @@ */ #include <linux/module.h> -#include <linux/init.h> #include <linux/netdevice.h> #include <linux/ctype.h> #include <linux/ethtool.h> diff --git a/drivers/net/usb/cdc_subset.c b/drivers/net/usb/cdc_subset.c index 0d1fe89ae0bd..91f0919fe278 100644 --- a/drivers/net/usb/cdc_subset.c +++ b/drivers/net/usb/cdc_subset.c @@ -13,13 +13,11 @@ * 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 + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/module.h> #include <linux/kmod.h> -#include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> diff --git a/drivers/net/usb/cx82310_eth.c b/drivers/net/usb/cx82310_eth.c index 1e207f086b75..3eed708a6182 100644 --- a/drivers/net/usb/cx82310_eth.c +++ b/drivers/net/usb/cx82310_eth.c @@ -14,12 +14,10 @@ * 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 + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/module.h> -#include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index c6867f926cff..6e9c344c7a20 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c @@ -1,5 +1,5 @@ /* - * Davicom DM9601 USB 1.1 10/100Mbps ethernet devices + * Davicom DM96xx USB 10/100Mbps ethernet devices * * Peter Korsgaard <jacmet@sunsite.dk> * @@ -13,7 +13,6 @@ #include <linux/module.h> #include <linux/sched.h> #include <linux/stddef.h> -#include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> @@ -364,7 +363,12 @@ static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf) dev->net->ethtool_ops = &dm9601_ethtool_ops; dev->net->hard_header_len += DM_TX_OVERHEAD; dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len; - dev->rx_urb_size = dev->net->mtu + ETH_HLEN + DM_RX_OVERHEAD; + + /* dm9620/21a require room for 4 byte padding, even in dm9601 + * mode, so we need +1 to be able to receive full size + * ethernet frames. + */ + dev->rx_urb_size = dev->net->mtu + ETH_HLEN + DM_RX_OVERHEAD + 1; dev->mii.dev = dev->net; dev->mii.mdio_read = dm9601_mdio_read; @@ -468,7 +472,7 @@ static int dm9601_rx_fixup(struct usbnet *dev, struct sk_buff *skb) static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { - int len; + int len, pad; /* format: b1: packet length low @@ -476,12 +480,23 @@ static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb, b3..n: packet data */ - len = skb->len; + len = skb->len + DM_TX_OVERHEAD; - if (skb_headroom(skb) < DM_TX_OVERHEAD) { + /* workaround for dm962x errata with tx fifo getting out of + * sync if a USB bulk transfer retry happens right after a + * packet with odd / maxpacket length by adding up to 3 bytes + * padding. + */ + while ((len & 1) || !(len % dev->maxpacket)) + len++; + + len -= DM_TX_OVERHEAD; /* hw header doesn't count as part of length */ + pad = len - skb->len; + + if (skb_headroom(skb) < DM_TX_OVERHEAD || skb_tailroom(skb) < pad) { struct sk_buff *skb2; - skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, 0, flags); + skb2 = skb_copy_expand(skb, DM_TX_OVERHEAD, pad, flags); dev_kfree_skb_any(skb); skb = skb2; if (!skb) @@ -490,10 +505,10 @@ static struct sk_buff *dm9601_tx_fixup(struct usbnet *dev, struct sk_buff *skb, __skb_push(skb, DM_TX_OVERHEAD); - /* usbnet adds padding if length is a multiple of packet size - if so, adjust length value in header */ - if ((skb->len % dev->maxpacket) == 0) - len++; + if (pad) { + memset(skb->data + skb->len, 0, pad); + __skb_put(skb, pad); + } skb->data[0] = len; skb->data[1] = len >> 8; @@ -543,7 +558,7 @@ static int dm9601_link_reset(struct usbnet *dev) } static const struct driver_info dm9601_info = { - .description = "Davicom DM9601 USB Ethernet", + .description = "Davicom DM96xx USB 10/100 Ethernet", .flags = FLAG_ETHER | FLAG_LINK_INTR, .bind = dm9601_bind, .rx_fixup = dm9601_rx_fixup, @@ -594,6 +609,22 @@ static const struct usb_device_id products[] = { USB_DEVICE(0x0a46, 0x9620), /* DM9620 USB to Fast Ethernet Adapter */ .driver_info = (unsigned long)&dm9601_info, }, + { + USB_DEVICE(0x0a46, 0x9621), /* DM9621A USB to Fast Ethernet Adapter */ + .driver_info = (unsigned long)&dm9601_info, + }, + { + USB_DEVICE(0x0a46, 0x9622), /* DM9622 USB to Fast Ethernet Adapter */ + .driver_info = (unsigned long)&dm9601_info, + }, + { + USB_DEVICE(0x0a46, 0x0269), /* DM962OA USB to Fast Ethernet Adapter */ + .driver_info = (unsigned long)&dm9601_info, + }, + { + USB_DEVICE(0x0a46, 0x1269), /* DM9621A USB to Fast Ethernet Adapter */ + .driver_info = (unsigned long)&dm9601_info, + }, {}, // END }; @@ -612,5 +643,5 @@ static struct usb_driver dm9601_driver = { module_usb_driver(dm9601_driver); MODULE_AUTHOR("Peter Korsgaard <jacmet@sunsite.dk>"); -MODULE_DESCRIPTION("Davicom DM9601 USB 1.1 ethernet devices"); +MODULE_DESCRIPTION("Davicom DM96xx USB 10/100 ethernet devices"); MODULE_LICENSE("GPL"); diff --git a/drivers/net/usb/gl620a.c b/drivers/net/usb/gl620a.c index a7e3f4e55bf3..1cc24e6f23e2 100644 --- a/drivers/net/usb/gl620a.c +++ b/drivers/net/usb/gl620a.c @@ -14,15 +14,13 @@ * 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 + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ // #define DEBUG // error path messages, extra info // #define VERBOSE // more; success messages #include <linux/module.h> -#include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> @@ -86,6 +84,10 @@ static int genelink_rx_fixup(struct usbnet *dev, struct sk_buff *skb) u32 size; u32 count; + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + header = (struct gl_header *) skb->data; // get the packet count of the received skb diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 86292e6aaf49..660bd5ea9fc0 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -185,7 +185,6 @@ enum rx_ctrl_state{ #define BM_REQUEST_TYPE (0xa1) #define B_NOTIFICATION (0x20) #define W_VALUE (0x0) -#define W_INDEX (0x2) #define W_LENGTH (0x2) #define B_OVERRUN (0x1<<6) @@ -1202,16 +1201,18 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb) struct hso_serial *serial = urb->context; int status = urb->status; + D4("\n--- Got serial_read_bulk callback %02x ---", status); + /* sanity check */ if (!serial) { D1("serial == NULL"); return; - } else if (status) { + } + if (status) { handle_usb_error(status, __func__, serial->parent); return; } - D4("\n--- Got serial_read_bulk callback %02x ---", status); D1("Actual length = %d\n", urb->actual_length); DUMP1(urb->transfer_buffer, urb->actual_length); @@ -1219,25 +1220,13 @@ static void hso_std_serial_read_bulk_callback(struct urb *urb) if (serial->port.count == 0) return; - if (status == 0) { - if (serial->parent->port_spec & HSO_INFO_CRC_BUG) - fix_crc_bug(urb, serial->in_endp->wMaxPacketSize); - /* Valid data, handle RX data */ - spin_lock(&serial->serial_lock); - serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1; - put_rxbuf_data_and_resubmit_bulk_urb(serial); - spin_unlock(&serial->serial_lock); - } else if (status == -ENOENT || status == -ECONNRESET) { - /* Unlinked - check for throttled port. */ - D2("Port %d, successfully unlinked urb", serial->minor); - spin_lock(&serial->serial_lock); - serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 0; - hso_resubmit_rx_bulk_urb(serial, urb); - spin_unlock(&serial->serial_lock); - } else { - D2("Port %d, status = %d for read urb", serial->minor, status); - return; - } + if (serial->parent->port_spec & HSO_INFO_CRC_BUG) + fix_crc_bug(urb, serial->in_endp->wMaxPacketSize); + /* Valid data, handle RX data */ + spin_lock(&serial->serial_lock); + serial->rx_urb_filled[hso_urb_to_index(serial, urb)] = 1; + put_rxbuf_data_and_resubmit_bulk_urb(serial); + spin_unlock(&serial->serial_lock); } /* @@ -1487,6 +1476,7 @@ static void tiocmget_intr_callback(struct urb *urb) struct uart_icount *icount; struct hso_serial_state_notification *serial_state_notification; struct usb_device *usb; + int if_num; /* Sanity checks */ if (!serial) @@ -1495,15 +1485,24 @@ static void tiocmget_intr_callback(struct urb *urb) handle_usb_error(status, __func__, serial->parent); return; } + + /* tiocmget is only supported on HSO_PORT_MODEM */ tiocmget = serial->tiocmget; if (!tiocmget) return; + BUG_ON((serial->parent->port_spec & HSO_PORT_MASK) != HSO_PORT_MODEM); + usb = serial->parent->usb; + if_num = serial->parent->interface->altsetting->desc.bInterfaceNumber; + + /* wIndex should be the USB interface number of the port to which the + * notification applies, which should always be the Modem port. + */ serial_state_notification = &tiocmget->serial_state_notification; if (serial_state_notification->bmRequestType != BM_REQUEST_TYPE || serial_state_notification->bNotification != B_NOTIFICATION || le16_to_cpu(serial_state_notification->wValue) != W_VALUE || - le16_to_cpu(serial_state_notification->wIndex) != W_INDEX || + le16_to_cpu(serial_state_notification->wIndex) != if_num || le16_to_cpu(serial_state_notification->wLength) != W_LENGTH) { dev_warn(&usb->dev, "hso received invalid serial state notification\n"); diff --git a/drivers/net/usb/int51x1.c b/drivers/net/usb/int51x1.c index ace9e74ffbdd..4ff70b22c6ee 100644 --- a/drivers/net/usb/int51x1.c +++ b/drivers/net/usb/int51x1.c @@ -20,8 +20,7 @@ * 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 + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/module.h> diff --git a/drivers/net/usb/ipheth.c b/drivers/net/usb/ipheth.c index ff8594d8dd2d..421934c83f1c 100644 --- a/drivers/net/usb/ipheth.c +++ b/drivers/net/usb/ipheth.c @@ -45,7 +45,6 @@ #include <linux/kernel.h> #include <linux/errno.h> -#include <linux/init.h> #include <linux/slab.h> #include <linux/module.h> #include <linux/netdevice.h> diff --git a/drivers/net/usb/kalmia.c b/drivers/net/usb/kalmia.c index 6866eae3e388..5662babf0583 100644 --- a/drivers/net/usb/kalmia.c +++ b/drivers/net/usb/kalmia.c @@ -15,7 +15,6 @@ */ #include <linux/module.h> -#include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ctype.h> diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index afb117c16d2d..a359d3bb7c5b 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -25,8 +25,7 @@ * 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. + * along with this program; if not, see <http://www.gnu.org/licenses/>. * ****************************************************************/ @@ -46,7 +45,6 @@ #include <linux/module.h> #include <linux/slab.h> #include <linux/string.h> -#include <linux/init.h> #include <linux/delay.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> diff --git a/drivers/net/usb/lg-vl600.c b/drivers/net/usb/lg-vl600.c index 808d6506da41..acfcc32b323d 100644 --- a/drivers/net/usb/lg-vl600.c +++ b/drivers/net/usb/lg-vl600.c @@ -15,8 +15,7 @@ * 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 + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/etherdevice.h> #include <linux/ethtool.h> diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index 03832d3780aa..82d844a8ebd0 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -36,14 +36,12 @@ * 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 + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/crc32.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> -#include <linux/init.h> #include <linux/mii.h> #include <linux/module.h> #include <linux/netdevice.h> @@ -117,7 +115,6 @@ enum { struct mcs7830_data { u8 multi_filter[8]; u8 config; - u8 link_counter; }; static const char driver_name[] = "MOSCHIP usb-ethernet driver"; @@ -529,8 +526,9 @@ static int mcs7830_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { u8 status; - if (skb->len == 0) { - dev_err(&dev->udev->dev, "unexpected empty rx frame\n"); + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) { + dev_err(&dev->udev->dev, "unexpected tiny rx frame\n"); return 0; } @@ -561,26 +559,16 @@ static void mcs7830_status(struct usbnet *dev, struct urb *urb) { u8 *buf = urb->transfer_buffer; bool link, link_changed; - struct mcs7830_data *data = mcs7830_get_data(dev); if (urb->actual_length < 16) return; - link = !(buf[1] & 0x20); + link = !(buf[1] == 0x20); link_changed = netif_carrier_ok(dev->net) != link; if (link_changed) { - data->link_counter++; - /* - track link state 20 times to guard against erroneous - link state changes reported sometimes by the chip - */ - if (data->link_counter > 20) { - data->link_counter = 0; - usbnet_link_change(dev, link, 0); - netdev_dbg(dev->net, "Link Status is: %d\n", link); - } - } else - data->link_counter = 0; + usbnet_link_change(dev, link, 0); + netdev_dbg(dev->net, "Link Status is: %d\n", link); + } } static const struct driver_info moschip_info = { diff --git a/drivers/net/usb/net1080.c b/drivers/net/usb/net1080.c index 93e0716a118c..4cbdb1307f3e 100644 --- a/drivers/net/usb/net1080.c +++ b/drivers/net/usb/net1080.c @@ -13,15 +13,13 @@ * 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 + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ // #define DEBUG // error path messages, extra info // #define VERBOSE // more; success messages #include <linux/module.h> -#include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> @@ -366,6 +364,10 @@ static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb) struct nc_trailer *trailer; u16 hdr_len, packet_len; + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + if (!(skb->len & 0x01)) { netdev_dbg(dev->net, "rx framesize %d range %d..%d mtu %d\n", skb->len, dev->net->hard_header_len, dev->hard_mtu, diff --git a/drivers/net/usb/plusb.c b/drivers/net/usb/plusb.c index 0fcc8e65a068..3d18bb0eee85 100644 --- a/drivers/net/usb/plusb.c +++ b/drivers/net/usb/plusb.c @@ -13,15 +13,13 @@ * 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 + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ // #define DEBUG // error path messages, extra info // #define VERBOSE // more; success messages #include <linux/module.h> -#include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c index 23bdd5b9274d..313cb6cd4848 100644 --- a/drivers/net/usb/qmi_wwan.c +++ b/drivers/net/usb/qmi_wwan.c @@ -80,10 +80,10 @@ static int qmi_wwan_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { __be16 proto; - /* usbnet rx_complete guarantees that skb->len is at least - * hard_header_len, so we can inspect the dest address without - * checking skb->len - */ + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + switch (skb->data[0] & 0xf0) { case 0x40: proto = htons(ETH_P_IP); @@ -712,6 +712,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x19d2, 0x1255, 3)}, {QMI_FIXED_INTF(0x19d2, 0x1255, 4)}, {QMI_FIXED_INTF(0x19d2, 0x1256, 4)}, + {QMI_FIXED_INTF(0x19d2, 0x1270, 5)}, /* ZTE MF667 */ {QMI_FIXED_INTF(0x19d2, 0x1401, 2)}, {QMI_FIXED_INTF(0x19d2, 0x1402, 2)}, /* ZTE MF60 */ {QMI_FIXED_INTF(0x19d2, 0x1424, 2)}, @@ -723,6 +724,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x1199, 0x68a2, 8)}, /* Sierra Wireless MC7710 in QMI mode */ {QMI_FIXED_INTF(0x1199, 0x68a2, 19)}, /* Sierra Wireless MC7710 in QMI mode */ {QMI_FIXED_INTF(0x1199, 0x901c, 8)}, /* Sierra Wireless EM7700 */ + {QMI_FIXED_INTF(0x1199, 0x9051, 8)}, /* Netgear AirCard 340U */ {QMI_FIXED_INTF(0x1bbb, 0x011e, 4)}, /* Telekom Speedstick LTE II (Alcatel One Touch L100V LTE) */ {QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */ {QMI_FIXED_INTF(0x2357, 0x9000, 4)}, /* TP-LINK MA260 */ @@ -730,6 +732,7 @@ static const struct usb_device_id products[] = { {QMI_FIXED_INTF(0x1bc7, 0x1201, 2)}, /* Telit LE920 */ {QMI_FIXED_INTF(0x0b3c, 0xc005, 6)}, /* Olivetti Olicard 200 */ {QMI_FIXED_INTF(0x1e2d, 0x0060, 4)}, /* Cinterion PLxx */ + {QMI_FIXED_INTF(0x1e2d, 0x0053, 4)}, /* Cinterion PHxx,PXxx */ /* 4. Gobi 1000 devices */ {QMI_GOBI1K_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c index 51073721e224..d89dbe395ad2 100644 --- a/drivers/net/usb/r8152.c +++ b/drivers/net/usb/r8152.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Realtek Semiconductor Corp. All rights reserved. + * Copyright (c) 2014 Realtek Semiconductor Corp. All rights reserved. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -7,7 +7,6 @@ * */ -#include <linux/init.h> #include <linux/signal.h> #include <linux/slab.h> #include <linux/module.h> @@ -24,9 +23,9 @@ #include <linux/ipv6.h> /* Version Information */ -#define DRIVER_VERSION "v1.02.0 (2013/10/28)" +#define DRIVER_VERSION "v1.04.0 (2014/01/15)" #define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>" -#define DRIVER_DESC "Realtek RTL8152 Based USB 2.0 Ethernet Adapters" +#define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters" #define MODULENAME "r8152" #define R8152_PHY_ID 32 @@ -39,15 +38,24 @@ #define PLA_RXFIFO_CTRL2 0xc0a8 #define PLA_FMC 0xc0b4 #define PLA_CFG_WOL 0xc0b6 +#define PLA_TEREDO_CFG 0xc0bc #define PLA_MAR 0xcd00 +#define PLA_BACKUP 0xd000 #define PAL_BDC_CR 0xd1a0 +#define PLA_TEREDO_TIMER 0xd2cc +#define PLA_REALWOW_TIMER 0xd2e8 #define PLA_LEDSEL 0xdd90 #define PLA_LED_FEATURE 0xdd92 #define PLA_PHYAR 0xde00 +#define PLA_BOOT_CTRL 0xe004 #define PLA_GPHY_INTR_IMR 0xe022 #define PLA_EEE_CR 0xe040 #define PLA_EEEP_CR 0xe080 #define PLA_MAC_PWR_CTRL 0xe0c0 +#define PLA_MAC_PWR_CTRL2 0xe0ca +#define PLA_MAC_PWR_CTRL3 0xe0cc +#define PLA_MAC_PWR_CTRL4 0xe0ce +#define PLA_WDT6_CTRL 0xe428 #define PLA_TCR0 0xe610 #define PLA_TCR1 0xe612 #define PLA_TXFIFO_CTRL 0xe618 @@ -73,16 +81,25 @@ #define PLA_BP_5 0xfc32 #define PLA_BP_6 0xfc34 #define PLA_BP_7 0xfc36 +#define PLA_BP_EN 0xfc38 +#define USB_U2P3_CTRL 0xb460 #define USB_DEV_STAT 0xb808 #define USB_USB_CTRL 0xd406 #define USB_PHY_CTRL 0xd408 #define USB_TX_AGG 0xd40a #define USB_RX_BUF_TH 0xd40c #define USB_USB_TIMER 0xd428 +#define USB_RX_EARLY_AGG 0xd42c #define USB_PM_CTRL_STATUS 0xd432 #define USB_TX_DMA 0xd434 +#define USB_TOLERANCE 0xd490 +#define USB_LPM_CTRL 0xd41a #define USB_UPS_CTRL 0xd800 +#define USB_MISC_0 0xd81a +#define USB_POWER_CUT 0xd80a +#define USB_AFE_CTRL2 0xd824 +#define USB_WDT11_CTRL 0xe43c #define USB_BP_BA 0xfc26 #define USB_BP_0 0xfc28 #define USB_BP_1 0xfc2a @@ -92,14 +109,30 @@ #define USB_BP_5 0xfc32 #define USB_BP_6 0xfc34 #define USB_BP_7 0xfc36 +#define USB_BP_EN 0xfc38 /* OCP Registers */ #define OCP_ALDPS_CONFIG 0x2010 #define OCP_EEE_CONFIG1 0x2080 #define OCP_EEE_CONFIG2 0x2092 #define OCP_EEE_CONFIG3 0x2094 +#define OCP_BASE_MII 0xa400 #define OCP_EEE_AR 0xa41a #define OCP_EEE_DATA 0xa41c +#define OCP_PHY_STATUS 0xa420 +#define OCP_POWER_CFG 0xa430 +#define OCP_EEE_CFG 0xa432 +#define OCP_SRAM_ADDR 0xa436 +#define OCP_SRAM_DATA 0xa438 +#define OCP_DOWN_SPEED 0xa442 +#define OCP_EEE_CFG2 0xa5d0 +#define OCP_ADC_CFG 0xbc06 + +/* SRAM Register */ +#define SRAM_LPF_CFG 0x8012 +#define SRAM_10M_AMP1 0x8080 +#define SRAM_10M_AMP2 0x8082 +#define SRAM_IMPEDANCE 0x8084 /* PLA_RCR */ #define RCR_AAP 0x00000001 @@ -116,14 +149,17 @@ #define RXFIFO_THR2_FULL 0x00000060 #define RXFIFO_THR2_HIGH 0x00000038 #define RXFIFO_THR2_OOB 0x0000004a +#define RXFIFO_THR2_NORMAL 0x00a0 /* PLA_RXFIFO_CTRL2 */ #define RXFIFO_THR3_FULL 0x00000078 #define RXFIFO_THR3_HIGH 0x00000048 #define RXFIFO_THR3_OOB 0x0000005a +#define RXFIFO_THR3_NORMAL 0x0110 /* PLA_TXFIFO_CTRL */ #define TXFIFO_THR_NORMAL 0x00400008 +#define TXFIFO_THR_NORMAL2 0x01000008 /* PLA_FMC */ #define FMC_FCR_MCU_EN 0x0001 @@ -131,6 +167,9 @@ /* PLA_EEEP_CR */ #define EEEP_CR_EEEP_TX 0x0002 +/* PLA_WDT6_CTRL */ +#define WDT6_SET_MODE 0x0010 + /* PLA_TCR0 */ #define TCR0_TX_EMPTY 0x0800 #define TCR0_AUTO_FIFO 0x0080 @@ -168,6 +207,12 @@ /* PLA_CFG_WOL */ #define MAGIC_EN 0x0001 +/* PLA_TEREDO_CFG */ +#define TEREDO_SEL 0x8000 +#define TEREDO_WAKE_MASK 0x7f00 +#define TEREDO_RS_EVENT_MASK 0x00fe +#define OOB_TEREDO_EN 0x0001 + /* PAL_BDC_CR */ #define ALDPS_PROXY_MODE 0x0001 @@ -185,6 +230,25 @@ #define D3_CLK_GATED_EN 0x00004000 #define MCU_CLK_RATIO 0x07010f07 #define MCU_CLK_RATIO_MASK 0x0f0f0f0f +#define ALDPS_SPDWN_RATIO 0x0f87 + +/* PLA_MAC_PWR_CTRL2 */ +#define EEE_SPDWN_RATIO 0x8007 + +/* PLA_MAC_PWR_CTRL3 */ +#define PKT_AVAIL_SPDWN_EN 0x0100 +#define SUSPEND_SPDWN_EN 0x0004 +#define U1U2_SPDWN_EN 0x0002 +#define L1_SPDWN_EN 0x0001 + +/* PLA_MAC_PWR_CTRL4 */ +#define PWRSAVE_SPDWN_EN 0x1000 +#define RXDV_SPDWN_EN 0x0800 +#define TX10MIDLE_EN 0x0100 +#define TP100_SPDWN_EN 0x0020 +#define TP500_SPDWN_EN 0x0010 +#define TP1000_SPDWN_EN 0x0008 +#define EEE_SPDWN_EN 0x0001 /* PLA_GPHY_INTR_IMR */ #define GPHY_STS_MSK 0x0001 @@ -199,6 +263,9 @@ #define EEE_RX_EN 0x0001 #define EEE_TX_EN 0x0002 +/* PLA_BOOT_CTRL */ +#define AUTOLOAD_DONE 0x0002 + /* USB_DEV_STAT */ #define STAT_SPEED_MASK 0x0006 #define STAT_SPEED_HIGH 0x0000 @@ -208,7 +275,9 @@ #define TX_AGG_MAX_THRESHOLD 0x03 /* USB_RX_BUF_TH */ -#define RX_BUF_THR 0x7a120180 +#define RX_THR_SUPPER 0x0c350180 +#define RX_THR_HIGH 0x7a120180 +#define RX_THR_SLOW 0xffff0180 /* USB_TX_DMA */ #define TEST_MODE_DISABLE 0x00000001 @@ -218,17 +287,55 @@ #define POWER_CUT 0x0100 /* USB_PM_CTRL_STATUS */ -#define RWSUME_INDICATE 0x0001 +#define RESUME_INDICATE 0x0001 /* USB_USB_CTRL */ #define RX_AGG_DISABLE 0x0010 +/* USB_U2P3_CTRL */ +#define U2P3_ENABLE 0x0001 + +/* USB_POWER_CUT */ +#define PWR_EN 0x0001 +#define PHASE2_EN 0x0008 + +/* USB_MISC_0 */ +#define PCUT_STATUS 0x0001 + +/* USB_RX_EARLY_AGG */ +#define EARLY_AGG_SUPPER 0x0e832981 +#define EARLY_AGG_HIGH 0x0e837a12 +#define EARLY_AGG_SLOW 0x0e83ffff + +/* USB_WDT11_CTRL */ +#define TIMER11_EN 0x0001 + +/* USB_LPM_CTRL */ +#define LPM_TIMER_MASK 0x0c +#define LPM_TIMER_500MS 0x04 /* 500 ms */ +#define LPM_TIMER_500US 0x0c /* 500 us */ + +/* USB_AFE_CTRL2 */ +#define SEN_VAL_MASK 0xf800 +#define SEN_VAL_NORMAL 0xa000 +#define SEL_RXIDLE 0x0100 + /* OCP_ALDPS_CONFIG */ #define ENPWRSAVE 0x8000 #define ENPDNPS 0x0200 #define LINKENA 0x0100 #define DIS_SDSAVE 0x0010 +/* OCP_PHY_STATUS */ +#define PHY_STAT_MASK 0x0007 +#define PHY_STAT_LAN_ON 3 +#define PHY_STAT_PWRDN 5 + +/* OCP_POWER_CFG */ +#define EEE_CLKDIV_EN 0x8000 +#define EN_ALDPS 0x0004 +#define EN_10M_PLLOFF 0x0001 + /* OCP_EEE_CONFIG1 */ #define RG_TXLPI_MSK_HFDUP 0x8000 #define RG_MATCLR_EN 0x4000 @@ -263,7 +370,36 @@ #define EEE_ADDR 0x003C #define EEE_DATA 0x0002 +/* OCP_EEE_CFG */ +#define CTAP_SHORT_EN 0x0040 +#define EEE10_EN 0x0010 + +/* OCP_DOWN_SPEED */ +#define EN_10M_BGOFF 0x0080 + +/* OCP_EEE_CFG2 */ +#define MY1000_EEE 0x0004 +#define MY100_EEE 0x0002 + +/* OCP_ADC_CFG */ +#define CKADSEL_L 0x0100 +#define ADC_EN 0x0080 +#define EN_EMI_L 0x0040 + +/* SRAM_LPF_CFG */ +#define LPF_AUTO_TUNE 0x8000 + +/* SRAM_10M_AMP1 */ +#define GDAC_IB_UPALL 0x0008 + +/* SRAM_10M_AMP2 */ +#define AMP_DN 0x0200 + +/* SRAM_IMPEDANCE */ +#define RX_DRIVING_MASK 0x6000 + enum rtl_register_content { + _1000bps = 0x10, _100bps = 0x08, _10bps = 0x04, LINK_STATUS = 0x02, @@ -273,6 +409,9 @@ enum rtl_register_content { #define RTL8152_MAX_TX 10 #define RTL8152_MAX_RX 10 #define INTBUFSIZE 2 +#define CRC_SIZE 4 +#define TX_ALIGN 4 +#define RX_ALIGN 8 #define INTR_LINK 0x0004 @@ -302,10 +441,17 @@ enum rtl8152_flags { /* Define these values to match your device */ #define VENDOR_ID_REALTEK 0x0bda #define PRODUCT_ID_RTL8152 0x8152 +#define PRODUCT_ID_RTL8153 0x8153 + +#define VENDOR_ID_SAMSUNG 0x04e8 +#define PRODUCT_ID_SAMSUNG 0xa101 #define MCU_TYPE_PLA 0x0100 #define MCU_TYPE_USB 0x0000 +#define REALTEK_USB_DEVICE(vend, prod) \ + USB_DEVICE_INTERFACE_CLASS(vend, prod, USB_CLASS_VENDOR_SPEC) + struct rx_desc { __le32 opts1; #define RX_LEN_MASK 0x7fff @@ -363,6 +509,15 @@ struct r8152 { spinlock_t rx_lock, tx_lock; struct delayed_work schedule; struct mii_if_info mii; + + struct rtl_ops { + void (*init)(struct r8152 *); + int (*enable)(struct r8152 *); + void (*disable)(struct r8152 *); + void (*down)(struct r8152 *); + void (*unload)(struct r8152 *); + } rtl_ops; + int intr_interval; u32 msg_enable; u32 tx_qlen; @@ -375,7 +530,11 @@ struct r8152 { enum rtl_version { RTL_VER_UNKNOWN = 0, RTL_VER_01, - RTL_VER_02 + RTL_VER_02, + RTL_VER_03, + RTL_VER_04, + RTL_VER_05, + RTL_VER_MAX }; /* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). @@ -427,8 +586,8 @@ int set_registers(struct r8152 *tp, u16 value, u16 index, u16 size, void *data) static int generic_ocp_read(struct r8152 *tp, u16 index, u16 size, void *data, u16 type) { - u16 limit = 64; - int ret = 0; + u16 limit = 64; + int ret = 0; if (test_bit(RTL8152_UNPLUG, &tp->flags)) return -ENODEV; @@ -467,9 +626,9 @@ static int generic_ocp_read(struct r8152 *tp, u16 index, u16 size, static int generic_ocp_write(struct r8152 *tp, u16 index, u16 byteen, u16 size, void *data, u16 type) { - int ret; - u16 byteen_start, byteen_end, byen; - u16 limit = 512; + int ret; + u16 byteen_start, byteen_end, byen; + u16 limit = 512; if (test_bit(RTL8152_UNPLUG, &tp->flags)) return -ENODEV; @@ -653,45 +812,54 @@ static void ocp_write_byte(struct r8152 *tp, u16 type, u16 index, u32 data) generic_ocp_write(tp, index, byen, sizeof(tmp), &tmp, type); } -static void r8152_mdio_write(struct r8152 *tp, u32 reg_addr, u32 value) +static u16 ocp_reg_read(struct r8152 *tp, u16 addr) { - u32 ocp_data; - int i; + u16 ocp_base, ocp_index; - ocp_data = PHYAR_FLAG | ((reg_addr & 0x1f) << 16) | - (value & 0xffff); + ocp_base = addr & 0xf000; + if (ocp_base != tp->ocp_base) { + ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base); + tp->ocp_base = ocp_base; + } - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_PHYAR, ocp_data); + ocp_index = (addr & 0x0fff) | 0xb000; + return ocp_read_word(tp, MCU_TYPE_PLA, ocp_index); +} - for (i = 20; i > 0; i--) { - udelay(25); - ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_PHYAR); - if (!(ocp_data & PHYAR_FLAG)) - break; +static void ocp_reg_write(struct r8152 *tp, u16 addr, u16 data) +{ + u16 ocp_base, ocp_index; + + ocp_base = addr & 0xf000; + if (ocp_base != tp->ocp_base) { + ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base); + tp->ocp_base = ocp_base; } - udelay(20); + + ocp_index = (addr & 0x0fff) | 0xb000; + ocp_write_word(tp, MCU_TYPE_PLA, ocp_index, data); } -static int r8152_mdio_read(struct r8152 *tp, u32 reg_addr) +static inline void r8152_mdio_write(struct r8152 *tp, u32 reg_addr, u32 value) { - u32 ocp_data; - int i; - - ocp_data = (reg_addr & 0x1f) << 16; - ocp_write_dword(tp, MCU_TYPE_PLA, PLA_PHYAR, ocp_data); + ocp_reg_write(tp, OCP_BASE_MII + reg_addr * 2, value); +} - for (i = 20; i > 0; i--) { - udelay(25); - ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_PHYAR); - if (ocp_data & PHYAR_FLAG) - break; - } - udelay(20); +static inline int r8152_mdio_read(struct r8152 *tp, u32 reg_addr) +{ + return ocp_reg_read(tp, OCP_BASE_MII + reg_addr * 2); +} - if (!(ocp_data & PHYAR_FLAG)) - return -EAGAIN; +static void sram_write(struct r8152 *tp, u16 addr, u16 data) +{ + ocp_reg_write(tp, OCP_SRAM_ADDR, addr); + ocp_reg_write(tp, OCP_SRAM_DATA, data); +} - return (u16)(ocp_data & 0xffff); +static u16 sram_read(struct r8152 *tp, u16 addr) +{ + ocp_reg_write(tp, OCP_SRAM_ADDR, addr); + return ocp_reg_read(tp, OCP_SRAM_DATA); } static int read_mii_word(struct net_device *netdev, int phy_id, int reg) @@ -715,20 +883,6 @@ void write_mii_word(struct net_device *netdev, int phy_id, int reg, int val) r8152_mdio_write(tp, reg, val); } -static void ocp_reg_write(struct r8152 *tp, u16 addr, u16 data) -{ - u16 ocp_base, ocp_index; - - ocp_base = addr & 0xf000; - if (ocp_base != tp->ocp_base) { - ocp_write_word(tp, MCU_TYPE_PLA, PLA_OCP_GPHY_BASE, ocp_base); - tp->ocp_base = ocp_base; - } - - ocp_index = (addr & 0x0fff) | 0xb000; - ocp_write_word(tp, MCU_TYPE_PLA, ocp_index, data); -} - static int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags); @@ -814,10 +968,12 @@ static void read_bulk_callback(struct urb *urb) case -ENOENT: return; /* the urb is in unlink state */ case -ETIME: - pr_warn_ratelimited("may be reset is needed?..\n"); + if (net_ratelimit()) + netdev_warn(netdev, "maybe reset is needed?\n"); break; default: - pr_warn_ratelimited("Rx status %d\n", status); + if (net_ratelimit()) + netdev_warn(netdev, "Rx status %d\n", status); break; } @@ -850,7 +1006,8 @@ static void write_bulk_callback(struct urb *urb) stats = rtl8152_get_stats(tp->netdev); if (status) { - pr_warn_ratelimited("Tx status %d\n", status); + if (net_ratelimit()) + netdev_warn(tp->netdev, "Tx status %d\n", status); stats->tx_errors += agg->skb_num; } else { stats->tx_packets += agg->skb_num; @@ -927,17 +1084,17 @@ resubmit: netif_device_detach(tp->netdev); else if (res) netif_err(tp, intr, tp->netdev, - "can't resubmit intr, status %d\n", res); + "can't resubmit intr, status %d\n", res); } static inline void *rx_agg_align(void *data) { - return (void *)ALIGN((uintptr_t)data, 8); + return (void *)ALIGN((uintptr_t)data, RX_ALIGN); } static inline void *tx_agg_align(void *data) { - return (void *)ALIGN((uintptr_t)data, 4); + return (void *)ALIGN((uintptr_t)data, TX_ALIGN); } static void free_all_mem(struct r8152 *tp) @@ -945,40 +1102,28 @@ static void free_all_mem(struct r8152 *tp) int i; for (i = 0; i < RTL8152_MAX_RX; i++) { - if (tp->rx_info[i].urb) { - usb_free_urb(tp->rx_info[i].urb); - tp->rx_info[i].urb = NULL; - } + usb_free_urb(tp->rx_info[i].urb); + tp->rx_info[i].urb = NULL; - if (tp->rx_info[i].buffer) { - kfree(tp->rx_info[i].buffer); - tp->rx_info[i].buffer = NULL; - tp->rx_info[i].head = NULL; - } + kfree(tp->rx_info[i].buffer); + tp->rx_info[i].buffer = NULL; + tp->rx_info[i].head = NULL; } for (i = 0; i < RTL8152_MAX_TX; i++) { - if (tp->tx_info[i].urb) { - usb_free_urb(tp->tx_info[i].urb); - tp->tx_info[i].urb = NULL; - } + usb_free_urb(tp->tx_info[i].urb); + tp->tx_info[i].urb = NULL; - if (tp->tx_info[i].buffer) { - kfree(tp->tx_info[i].buffer); - tp->tx_info[i].buffer = NULL; - tp->tx_info[i].head = NULL; - } + kfree(tp->tx_info[i].buffer); + tp->tx_info[i].buffer = NULL; + tp->tx_info[i].head = NULL; } - if (tp->intr_urb) { - usb_free_urb(tp->intr_urb); - tp->intr_urb = NULL; - } + usb_free_urb(tp->intr_urb); + tp->intr_urb = NULL; - if (tp->intr_buff) { - kfree(tp->intr_buff); - tp->intr_buff = NULL; - } + kfree(tp->intr_buff); + tp->intr_buff = NULL; } static int alloc_all_mem(struct r8152 *tp) @@ -1006,7 +1151,8 @@ static int alloc_all_mem(struct r8152 *tp) if (buf != rx_agg_align(buf)) { kfree(buf); - buf = kmalloc_node(rx_buf_sz + 8, GFP_KERNEL, node); + buf = kmalloc_node(rx_buf_sz + RX_ALIGN, GFP_KERNEL, + node); if (!buf) goto err1; } @@ -1031,7 +1177,8 @@ static int alloc_all_mem(struct r8152 *tp) if (buf != tx_agg_align(buf)) { kfree(buf); - buf = kmalloc_node(rx_buf_sz + 4, GFP_KERNEL, node); + buf = kmalloc_node(rx_buf_sz + TX_ALIGN, GFP_KERNEL, + node); if (!buf) goto err1; } @@ -1231,7 +1378,7 @@ static void rx_bottom(struct r8152 *tp) stats = rtl8152_get_stats(netdev); - pkt_len -= 4; /* CRC */ + pkt_len -= CRC_SIZE; rx_data += sizeof(struct rx_desc); skb = netdev_alloc_skb_ip_align(netdev, pkt_len); @@ -1246,7 +1393,7 @@ static void rx_bottom(struct r8152 *tp) stats->rx_packets++; stats->rx_bytes += pkt_len; - rx_data = rx_agg_align(rx_data + pkt_len + 4); + rx_data = rx_agg_align(rx_data + pkt_len + CRC_SIZE); rx_desc = (struct rx_desc *)rx_data; len_used = (int)(rx_data - (u8 *)agg->head); len_used += sizeof(struct rx_desc); @@ -1336,7 +1483,7 @@ static void rtl8152_tx_timeout(struct net_device *netdev) struct r8152 *tp = netdev_priv(netdev); int i; - netif_warn(tp, tx_err, netdev, "Tx timeout.\n"); + netif_warn(tp, tx_err, netdev, "Tx timeout\n"); for (i = 0; i < RTL8152_MAX_TX; i++) usb_unlink_urb(tp->tx_info[i].urb); } @@ -1449,13 +1596,11 @@ static inline u8 rtl8152_get_speed(struct r8152 *tp) return ocp_read_byte(tp, MCU_TYPE_PLA, PLA_PHYSTATUS); } -static int rtl8152_enable(struct r8152 *tp) +static void rtl_set_eee_plus(struct r8152 *tp) { u32 ocp_data; - int i, ret; u8 speed; - set_tx_qlen(tp); speed = rtl8152_get_speed(tp); if (speed & _10bps) { ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR); @@ -1466,6 +1611,12 @@ static int rtl8152_enable(struct r8152 *tp) ocp_data &= ~EEEP_CR_EEEP_TX; ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEEP_CR, ocp_data); } +} + +static int rtl_enable(struct r8152 *tp) +{ + u32 ocp_data; + int i, ret; r8152b_reset_packet_filter(tp); @@ -1487,6 +1638,47 @@ static int rtl8152_enable(struct r8152 *tp) return ret; } +static int rtl8152_enable(struct r8152 *tp) +{ + set_tx_qlen(tp); + rtl_set_eee_plus(tp); + + return rtl_enable(tp); +} + +static void r8153_set_rx_agg(struct r8152 *tp) +{ + u8 speed; + + speed = rtl8152_get_speed(tp); + if (speed & _1000bps) { + if (tp->udev->speed == USB_SPEED_SUPER) { + ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, + RX_THR_SUPPER); + ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_EARLY_AGG, + EARLY_AGG_SUPPER); + } else { + ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, + RX_THR_HIGH); + ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_EARLY_AGG, + EARLY_AGG_HIGH); + } + } else { + ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_SLOW); + ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_EARLY_AGG, + EARLY_AGG_SLOW); + } +} + +static int rtl8153_enable(struct r8152 *tp) +{ + set_tx_qlen(tp); + rtl_set_eee_plus(tp); + r8153_set_rx_agg(tp); + + return rtl_enable(tp); +} + static void rtl8152_disable(struct r8152 *tp) { struct net_device_stats *stats = rtl8152_get_stats(tp->netdev); @@ -1596,7 +1788,7 @@ static void r8152b_exit_oob(struct r8152 *tp) ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL); ocp_write_byte(tp, MCU_TYPE_USB, USB_TX_AGG, TX_AGG_MAX_THRESHOLD); - ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_BUF_THR); + ocp_write_dword(tp, MCU_TYPE_USB, USB_RX_BUF_TH, RX_THR_HIGH); ocp_write_dword(tp, MCU_TYPE_USB, USB_TX_DMA, TEST_MODE_DISABLE | TX_SIZE_ADJUST1); @@ -1613,8 +1805,8 @@ static void r8152b_exit_oob(struct r8152 *tp) static void r8152b_enter_oob(struct r8152 *tp) { - u32 ocp_data; - int i; + u32 ocp_data; + int i; ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); ocp_data &= ~NOW_IS_OOB; @@ -1685,15 +1877,269 @@ static inline void r8152b_enable_aldps(struct r8152 *tp) LINKENA | DIS_SDSAVE); } +static void r8153_hw_phy_cfg(struct r8152 *tp) +{ + u32 ocp_data; + u16 data; + + ocp_reg_write(tp, OCP_ADC_CFG, CKADSEL_L | ADC_EN | EN_EMI_L); + r8152_mdio_write(tp, MII_BMCR, BMCR_ANENABLE); + + if (tp->version == RTL_VER_03) { + data = ocp_reg_read(tp, OCP_EEE_CFG); + data &= ~CTAP_SHORT_EN; + ocp_reg_write(tp, OCP_EEE_CFG, data); + } + + data = ocp_reg_read(tp, OCP_POWER_CFG); + data |= EEE_CLKDIV_EN; + ocp_reg_write(tp, OCP_POWER_CFG, data); + + data = ocp_reg_read(tp, OCP_DOWN_SPEED); + data |= EN_10M_BGOFF; + ocp_reg_write(tp, OCP_DOWN_SPEED, data); + data = ocp_reg_read(tp, OCP_POWER_CFG); + data |= EN_10M_PLLOFF; + ocp_reg_write(tp, OCP_POWER_CFG, data); + data = sram_read(tp, SRAM_IMPEDANCE); + data &= ~RX_DRIVING_MASK; + sram_write(tp, SRAM_IMPEDANCE, data); + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR); + ocp_data |= PFM_PWM_SWITCH; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_PHY_PWR, ocp_data); + + data = sram_read(tp, SRAM_LPF_CFG); + data |= LPF_AUTO_TUNE; + sram_write(tp, SRAM_LPF_CFG, data); + + data = sram_read(tp, SRAM_10M_AMP1); + data |= GDAC_IB_UPALL; + sram_write(tp, SRAM_10M_AMP1, data); + data = sram_read(tp, SRAM_10M_AMP2); + data |= AMP_DN; + sram_write(tp, SRAM_10M_AMP2, data); +} + +static void r8153_u1u2en(struct r8152 *tp, int enable) +{ + u8 u1u2[8]; + + if (enable) + memset(u1u2, 0xff, sizeof(u1u2)); + else + memset(u1u2, 0x00, sizeof(u1u2)); + + usb_ocp_write(tp, USB_TOLERANCE, BYTE_EN_SIX_BYTES, sizeof(u1u2), u1u2); +} + +static void r8153_u2p3en(struct r8152 *tp, int enable) +{ + u32 ocp_data; + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL); + if (enable) + ocp_data |= U2P3_ENABLE; + else + ocp_data &= ~U2P3_ENABLE; + ocp_write_word(tp, MCU_TYPE_USB, USB_U2P3_CTRL, ocp_data); +} + +static void r8153_power_cut_en(struct r8152 *tp, int enable) +{ + u32 ocp_data; + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_POWER_CUT); + if (enable) + ocp_data |= PWR_EN | PHASE2_EN; + else + ocp_data &= ~(PWR_EN | PHASE2_EN); + ocp_write_word(tp, MCU_TYPE_USB, USB_POWER_CUT, ocp_data); + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_MISC_0); + ocp_data &= ~PCUT_STATUS; + ocp_write_word(tp, MCU_TYPE_USB, USB_MISC_0, ocp_data); +} + +static void r8153_teredo_off(struct r8152 *tp) +{ + u32 ocp_data; + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG); + ocp_data &= ~(TEREDO_SEL | TEREDO_RS_EVENT_MASK | OOB_TEREDO_EN); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data); + + ocp_write_word(tp, MCU_TYPE_PLA, PLA_WDT6_CTRL, WDT6_SET_MODE); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_REALWOW_TIMER, 0); + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TEREDO_TIMER, 0); +} + +static void r8153_first_init(struct r8152 *tp) +{ + u32 ocp_data; + int i; + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); + ocp_data |= RXDY_GATED_EN; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data); + + r8153_teredo_off(tp); + + ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); + ocp_data &= ~RCR_ACPT_ALL; + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); + + r8153_hw_phy_cfg(tp); + + rtl8152_nic_reset(tp); + + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); + ocp_data &= ~NOW_IS_OOB; + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); + ocp_data &= ~MCU_BORW_EN; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); + + for (i = 0; i < 1000; i++) { + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); + if (ocp_data & LINK_LIST_READY) + break; + mdelay(1); + } + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); + ocp_data |= RE_INIT_LL; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); + + for (i = 0; i < 1000; i++) { + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); + if (ocp_data & LINK_LIST_READY) + break; + mdelay(1); + } + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR); + ocp_data &= ~CPCR_RX_VLAN; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data); + + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS); + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TCR0); + ocp_data |= TCR0_AUTO_FIFO; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_TCR0, ocp_data); + + rtl8152_nic_reset(tp); + + /* rx share fifo credit full threshold */ + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL0, RXFIFO_THR1_NORMAL); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL1, RXFIFO_THR2_NORMAL); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RXFIFO_CTRL2, RXFIFO_THR3_NORMAL); + /* TX share fifo free credit full threshold */ + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_TXFIFO_CTRL, TXFIFO_THR_NORMAL2); + + /* rx aggregation */ + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_USB_CTRL); + ocp_data &= ~RX_AGG_DISABLE; + ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); +} + +static void r8153_enter_oob(struct r8152 *tp) +{ + u32 ocp_data; + int i; + + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); + ocp_data &= ~NOW_IS_OOB; + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); + + rtl8152_disable(tp); + + for (i = 0; i < 1000; i++) { + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); + if (ocp_data & LINK_LIST_READY) + break; + mdelay(1); + } + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7); + ocp_data |= RE_INIT_LL; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_SFF_STS_7, ocp_data); + + for (i = 0; i < 1000; i++) { + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); + if (ocp_data & LINK_LIST_READY) + break; + mdelay(1); + } + + ocp_write_word(tp, MCU_TYPE_PLA, PLA_RMS, RTL8152_RMS); + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL); + ocp_data |= MAGIC_EN; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_CFG_WOL, ocp_data); + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG); + ocp_data &= ~TEREDO_WAKE_MASK; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_TEREDO_CFG, ocp_data); + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_CPCR); + ocp_data |= CPCR_RX_VLAN; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_CPCR, ocp_data); + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PAL_BDC_CR); + ocp_data |= ALDPS_PROXY_MODE; + ocp_write_word(tp, MCU_TYPE_PLA, PAL_BDC_CR, ocp_data); + + ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL); + ocp_data |= NOW_IS_OOB | DIS_MCU_CLROOB; + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_OOB_CTRL, ocp_data); + + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_CONFIG5, LAN_WAKE_EN); + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_MISC_1); + ocp_data &= ~RXDY_GATED_EN; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MISC_1, ocp_data); + + ocp_data = ocp_read_dword(tp, MCU_TYPE_PLA, PLA_RCR); + ocp_data |= RCR_APM | RCR_AM | RCR_AB; + ocp_write_dword(tp, MCU_TYPE_PLA, PLA_RCR, ocp_data); +} + +static void r8153_disable_aldps(struct r8152 *tp) +{ + u16 data; + + data = ocp_reg_read(tp, OCP_POWER_CFG); + data &= ~EN_ALDPS; + ocp_reg_write(tp, OCP_POWER_CFG, data); + msleep(20); +} + +static void r8153_enable_aldps(struct r8152 *tp) +{ + u16 data; + + data = ocp_reg_read(tp, OCP_POWER_CFG); + data |= EN_ALDPS; + ocp_reg_write(tp, OCP_POWER_CFG, data); +} + static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex) { - u16 bmcr, anar; + u16 bmcr, anar, gbcr; int ret = 0; cancel_delayed_work_sync(&tp->schedule); anar = r8152_mdio_read(tp, MII_ADVERTISE); anar &= ~(ADVERTISE_10HALF | ADVERTISE_10FULL | ADVERTISE_100HALF | ADVERTISE_100FULL); + if (tp->mii.supports_gmii) { + gbcr = r8152_mdio_read(tp, MII_CTRL1000); + gbcr &= ~(ADVERTISE_1000FULL | ADVERTISE_1000HALF); + } else { + gbcr = 0; + } if (autoneg == AUTONEG_DISABLE) { if (speed == SPEED_10) { @@ -1702,6 +2148,9 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex) } else if (speed == SPEED_100) { bmcr = BMCR_SPEED100; anar |= ADVERTISE_100HALF | ADVERTISE_100FULL; + } else if (speed == SPEED_1000 && tp->mii.supports_gmii) { + bmcr = BMCR_SPEED1000; + gbcr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; } else { ret = -EINVAL; goto out; @@ -1723,6 +2172,16 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex) anar |= ADVERTISE_10HALF; anar |= ADVERTISE_100HALF; } + } else if (speed == SPEED_1000 && tp->mii.supports_gmii) { + if (duplex == DUPLEX_FULL) { + anar |= ADVERTISE_10HALF | ADVERTISE_10FULL; + anar |= ADVERTISE_100HALF | ADVERTISE_100FULL; + gbcr |= ADVERTISE_1000FULL | ADVERTISE_1000HALF; + } else { + anar |= ADVERTISE_10HALF; + anar |= ADVERTISE_100HALF; + gbcr |= ADVERTISE_1000HALF; + } } else { ret = -EINVAL; goto out; @@ -1731,6 +2190,9 @@ static int rtl8152_set_speed(struct r8152 *tp, u8 autoneg, u16 speed, u8 duplex) bmcr = BMCR_ANENABLE | BMCR_ANRESTART; } + if (tp->mii.supports_gmii) + r8152_mdio_write(tp, MII_CTRL1000, gbcr); + r8152_mdio_write(tp, MII_ADVERTISE, anar); r8152_mdio_write(tp, MII_BMCR, bmcr); @@ -1752,6 +2214,15 @@ static void rtl8152_down(struct r8152 *tp) r8152b_enable_aldps(tp); } +static void rtl8153_down(struct r8152 *tp) +{ + r8153_u1u2en(tp, 0); + r8153_power_cut_en(tp, 0); + r8153_disable_aldps(tp); + r8153_enter_oob(tp); + r8153_enable_aldps(tp); +} + static void set_carrier(struct r8152 *tp) { struct net_device *netdev = tp->netdev; @@ -1762,7 +2233,7 @@ static void set_carrier(struct r8152 *tp) if (speed & LINK_STATUS) { if (!(tp->speed & LINK_STATUS)) { - rtl8152_enable(tp); + tp->rtl_ops.enable(tp); set_bit(RTL8152_SET_RX_MODE, &tp->flags); netif_carrier_on(netdev); } @@ -1770,7 +2241,7 @@ static void set_carrier(struct r8152 *tp) if (tp->speed & LINK_STATUS) { netif_carrier_off(netdev); tasklet_disable(&tp->tl); - rtl8152_disable(tp); + tp->rtl_ops.disable(tp); tasklet_enable(&tp->tl); } } @@ -1802,20 +2273,21 @@ static int rtl8152_open(struct net_device *netdev) struct r8152 *tp = netdev_priv(netdev); int res = 0; + rtl8152_set_speed(tp, AUTONEG_ENABLE, + tp->mii.supports_gmii ? SPEED_1000 : SPEED_100, + DUPLEX_FULL); + tp->speed = 0; + netif_carrier_off(netdev); + netif_start_queue(netdev); + set_bit(WORK_ENABLE, &tp->flags); res = usb_submit_urb(tp->intr_urb, GFP_KERNEL); if (res) { if (res == -ENODEV) netif_device_detach(tp->netdev); - netif_warn(tp, ifup, netdev, - "intr_urb submit failed: %d\n", res); - return res; + netif_warn(tp, ifup, netdev, "intr_urb submit failed: %d\n", + res); } - rtl8152_set_speed(tp, AUTONEG_ENABLE, SPEED_100, DUPLEX_FULL); - tp->speed = 0; - netif_carrier_off(netdev); - netif_start_queue(netdev); - set_bit(WORK_ENABLE, &tp->flags); return res; } @@ -1825,12 +2297,12 @@ static int rtl8152_close(struct net_device *netdev) struct r8152 *tp = netdev_priv(netdev); int res = 0; - usb_kill_urb(tp->intr_urb); clear_bit(WORK_ENABLE, &tp->flags); + usb_kill_urb(tp->intr_urb); cancel_delayed_work_sync(&tp->schedule); netif_stop_queue(netdev); tasklet_disable(&tp->tl); - rtl8152_disable(tp); + tp->rtl_ops.disable(tp); tasklet_enable(&tp->tl); return res; @@ -1851,9 +2323,16 @@ static void rtl_clear_bp(struct r8152 *tp) ocp_write_word(tp, MCU_TYPE_USB, USB_BP_BA, 0); } +static void r8153_clear_bp(struct r8152 *tp) +{ + ocp_write_byte(tp, MCU_TYPE_PLA, PLA_BP_EN, 0); + ocp_write_byte(tp, MCU_TYPE_USB, USB_BP_EN, 0); + rtl_clear_bp(tp); +} + static void r8152b_enable_eee(struct r8152 *tp) { - u32 ocp_data; + u32 ocp_data; ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEE_CR); ocp_data |= EEE_RX_EN | EEE_TX_EN; @@ -1874,6 +2353,22 @@ static void r8152b_enable_eee(struct r8152 *tp) ocp_reg_write(tp, OCP_EEE_AR, 0x0000); } +static void r8153_enable_eee(struct r8152 *tp) +{ + u32 ocp_data; + u16 data; + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_EEE_CR); + ocp_data |= EEE_RX_EN | EEE_TX_EN; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_EEE_CR, ocp_data); + data = ocp_reg_read(tp, OCP_EEE_CFG); + data |= EEE10_EN; + ocp_reg_write(tp, OCP_EEE_CFG, data); + data = ocp_reg_read(tp, OCP_EEE_CFG2); + data |= MY1000_EEE | MY100_EEE; + ocp_reg_write(tp, OCP_EEE_CFG2, data); +} + static void r8152b_enable_fc(struct r8152 *tp) { u16 anar; @@ -1909,7 +2404,7 @@ static void r8152b_init(struct r8152 *tp) ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data); ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS); - ocp_data &= ~RWSUME_INDICATE; + ocp_data &= ~RESUME_INDICATE; ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data); r8152b_exit_oob(tp); @@ -1943,6 +2438,75 @@ static void r8152b_init(struct r8152 *tp) ocp_write_word(tp, MCU_TYPE_USB, USB_USB_CTRL, ocp_data); } +static void r8153_init(struct r8152 *tp) +{ + u32 ocp_data; + int i; + + r8153_u1u2en(tp, 0); + + for (i = 0; i < 500; i++) { + if (ocp_read_word(tp, MCU_TYPE_PLA, PLA_BOOT_CTRL) & + AUTOLOAD_DONE) + break; + msleep(20); + } + + for (i = 0; i < 500; i++) { + ocp_data = ocp_reg_read(tp, OCP_PHY_STATUS) & PHY_STAT_MASK; + if (ocp_data == PHY_STAT_LAN_ON || ocp_data == PHY_STAT_PWRDN) + break; + msleep(20); + } + + r8153_u2p3en(tp, 0); + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL); + ocp_data &= ~TIMER11_EN; + ocp_write_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL, ocp_data); + + r8153_clear_bp(tp); + + ocp_data = ocp_read_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE); + ocp_data &= ~LED_MODE_MASK; + ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data); + + ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL); + ocp_data &= ~LPM_TIMER_MASK; + if (tp->udev->speed == USB_SPEED_SUPER) + ocp_data |= LPM_TIMER_500US; + else + ocp_data |= LPM_TIMER_500MS; + ocp_write_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL, ocp_data); + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2); + ocp_data &= ~SEN_VAL_MASK; + ocp_data |= SEN_VAL_NORMAL | SEL_RXIDLE; + ocp_write_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2, ocp_data); + + r8153_power_cut_en(tp, 0); + r8153_u1u2en(tp, 1); + + r8153_first_init(tp); + + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL, ALDPS_SPDWN_RATIO); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL2, EEE_SPDWN_RATIO); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL3, + PKT_AVAIL_SPDWN_EN | SUSPEND_SPDWN_EN | + U1U2_SPDWN_EN | L1_SPDWN_EN); + ocp_write_word(tp, MCU_TYPE_PLA, PLA_MAC_PWR_CTRL4, + PWRSAVE_SPDWN_EN | RXDV_SPDWN_EN | TX10MIDLE_EN | + TP100_SPDWN_EN | TP500_SPDWN_EN | TP1000_SPDWN_EN | + EEE_SPDWN_EN); + + r8153_enable_eee(tp); + r8153_enable_aldps(tp); + r8152b_enable_fc(tp); + + r8152_mdio_write(tp, MII_BMCR, BMCR_RESET | BMCR_ANENABLE | + BMCR_ANRESTART); +} + static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) { struct r8152 *tp = usb_get_intfdata(intf); @@ -1956,7 +2520,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message) tasklet_disable(&tp->tl); } - rtl8152_down(tp); + tp->rtl_ops.down(tp); return 0; } @@ -1965,10 +2529,12 @@ static int rtl8152_resume(struct usb_interface *intf) { struct r8152 *tp = usb_get_intfdata(intf); - r8152b_init(tp); + tp->rtl_ops.init(tp); netif_device_attach(tp->netdev); if (netif_running(tp->netdev)) { - rtl8152_set_speed(tp, AUTONEG_ENABLE, SPEED_100, DUPLEX_FULL); + rtl8152_set_speed(tp, AUTONEG_ENABLE, + tp->mii.supports_gmii ? SPEED_1000 : SPEED_100, + DUPLEX_FULL); tp->speed = 0; netif_carrier_off(tp->netdev); set_bit(WORK_ENABLE, &tp->flags); @@ -2072,6 +2638,18 @@ static void r8152b_get_version(struct r8152 *tp) case 0x4c10: tp->version = RTL_VER_02; break; + case 0x5c00: + tp->version = RTL_VER_03; + tp->mii.supports_gmii = 1; + break; + case 0x5c10: + tp->version = RTL_VER_04; + tp->mii.supports_gmii = 1; + break; + case 0x5c20: + tp->version = RTL_VER_05; + tp->mii.supports_gmii = 1; + break; default: netif_info(tp, probe, tp->netdev, "Unknown version 0x%04x\n", version); @@ -2079,6 +2657,80 @@ static void r8152b_get_version(struct r8152 *tp) } } +static void rtl8152_unload(struct r8152 *tp) +{ + u32 ocp_data; + + if (tp->version != RTL_VER_01) { + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL); + ocp_data |= POWER_CUT; + ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data); + } + + ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS); + ocp_data &= ~RESUME_INDICATE; + ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data); +} + +static void rtl8153_unload(struct r8152 *tp) +{ + r8153_power_cut_en(tp, 1); +} + +static int rtl_ops_init(struct r8152 *tp, const struct usb_device_id *id) +{ + struct rtl_ops *ops = &tp->rtl_ops; + int ret = -ENODEV; + + switch (id->idVendor) { + case VENDOR_ID_REALTEK: + switch (id->idProduct) { + case PRODUCT_ID_RTL8152: + ops->init = r8152b_init; + ops->enable = rtl8152_enable; + ops->disable = rtl8152_disable; + ops->down = rtl8152_down; + ops->unload = rtl8152_unload; + ret = 0; + break; + case PRODUCT_ID_RTL8153: + ops->init = r8153_init; + ops->enable = rtl8153_enable; + ops->disable = rtl8152_disable; + ops->down = rtl8153_down; + ops->unload = rtl8153_unload; + ret = 0; + break; + default: + break; + } + break; + + case VENDOR_ID_SAMSUNG: + switch (id->idProduct) { + case PRODUCT_ID_SAMSUNG: + ops->init = r8153_init; + ops->enable = rtl8153_enable; + ops->disable = rtl8152_disable; + ops->down = rtl8153_down; + ops->unload = rtl8153_unload; + ret = 0; + break; + default: + break; + } + break; + + default: + break; + } + + if (ret) + netif_err(tp, probe, tp->netdev, "Unknown Device\n"); + + return ret; +} + static int rtl8152_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -2087,14 +2739,9 @@ static int rtl8152_probe(struct usb_interface *intf, struct net_device *netdev; int ret; - if (udev->actconfig->desc.bConfigurationValue != 1) { - usb_driver_set_configuration(udev, 1); - return -ENODEV; - } - netdev = alloc_etherdev(sizeof(struct r8152)); if (!netdev) { - dev_err(&intf->dev, "Out of memory"); + dev_err(&intf->dev, "Out of memory\n"); return -ENOMEM; } @@ -2102,12 +2749,17 @@ static int rtl8152_probe(struct usb_interface *intf, tp = netdev_priv(netdev); tp->msg_enable = 0x7FFF; - tasklet_init(&tp->tl, bottom_half, (unsigned long)tp); - INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t); - tp->udev = udev; tp->netdev = netdev; tp->intf = intf; + + ret = rtl_ops_init(tp, id); + if (ret) + goto out; + + tasklet_init(&tp->tl, bottom_half, (unsigned long)tp); + INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t); + netdev->netdev_ops = &rtl8152_netdev_ops; netdev->watchdog_timeo = RTL8152_TX_TIMEOUT; @@ -2124,7 +2776,7 @@ static int rtl8152_probe(struct usb_interface *intf, tp->mii.supports_gmii = 0; r8152b_get_version(tp); - r8152b_init(tp); + tp->rtl_ops.init(tp); set_ethernet_addr(tp); ret = alloc_all_mem(tp); @@ -2135,11 +2787,11 @@ static int rtl8152_probe(struct usb_interface *intf, ret = register_netdev(netdev); if (ret != 0) { - netif_err(tp, probe, netdev, "couldn't register the device"); + netif_err(tp, probe, netdev, "couldn't register the device\n"); goto out1; } - netif_info(tp, probe, netdev, "%s", DRIVER_VERSION); + netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION); return 0; @@ -2150,21 +2802,6 @@ out: return ret; } -static void rtl8152_unload(struct r8152 *tp) -{ - u32 ocp_data; - - if (tp->version != RTL_VER_01) { - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_UPS_CTRL); - ocp_data |= POWER_CUT; - ocp_write_word(tp, MCU_TYPE_USB, USB_UPS_CTRL, ocp_data); - } - - ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS); - ocp_data &= ~RWSUME_INDICATE; - ocp_write_word(tp, MCU_TYPE_USB, USB_PM_CTRL_STATUS, ocp_data); -} - static void rtl8152_disconnect(struct usb_interface *intf) { struct r8152 *tp = usb_get_intfdata(intf); @@ -2174,7 +2811,7 @@ static void rtl8152_disconnect(struct usb_interface *intf) set_bit(RTL8152_UNPLUG, &tp->flags); tasklet_kill(&tp->tl); unregister_netdev(tp->netdev); - rtl8152_unload(tp); + tp->rtl_ops.unload(tp); free_all_mem(tp); free_netdev(tp->netdev); } @@ -2182,7 +2819,9 @@ static void rtl8152_disconnect(struct usb_interface *intf) /* table of devices that work with this driver */ static struct usb_device_id rtl8152_table[] = { - {USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8152)}, + {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8152)}, + {REALTEK_USB_DEVICE(VENDOR_ID_REALTEK, PRODUCT_ID_RTL8153)}, + {REALTEK_USB_DEVICE(VENDOR_ID_SAMSUNG, PRODUCT_ID_SAMSUNG)}, {} }; diff --git a/drivers/net/usb/r815x.c b/drivers/net/usb/r815x.c index 2df2f4fb42a7..f0a8791b7636 100644 --- a/drivers/net/usb/r815x.c +++ b/drivers/net/usb/r815x.c @@ -216,21 +216,13 @@ static const struct usb_device_id products[] = { { USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8152, USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), -#if defined(CONFIG_USB_RTL8152) || defined(CONFIG_USB_RTL8152_MODULE) - .driver_info = 0, -#else .driver_info = (unsigned long) &r8152_info, -#endif }, { USB_DEVICE_AND_INTERFACE_INFO(REALTEK_VENDOR_ID, 0x8153, USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET, USB_CDC_PROTO_NONE), -#if defined(CONFIG_USB_RTL8153) || defined(CONFIG_USB_RTL8153_MODULE) - .driver_info = 0, -#else .driver_info = (unsigned long) &r8153_info, -#endif }, { }, /* END */ diff --git a/drivers/net/usb/rndis_host.c b/drivers/net/usb/rndis_host.c index cc49aac70224..524a47a28120 100644 --- a/drivers/net/usb/rndis_host.c +++ b/drivers/net/usb/rndis_host.c @@ -13,11 +13,9 @@ * 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 + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #include <linux/module.h> -#include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> @@ -494,6 +492,10 @@ EXPORT_SYMBOL_GPL(rndis_unbind); */ int rndis_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + /* peripheral may have batched packets to us... */ while (likely(skb->len)) { struct rndis_data_hdr *hdr = (void *)skb->data; diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index 6cbdac67f3a0..da2c4583bd2d 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -6,7 +6,6 @@ * version 2 as published by the Free Software Foundation. */ -#include <linux/init.h> #include <linux/signal.h> #include <linux/slab.h> #include <linux/module.h> diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c index a79e9d334928..a251588762ec 100644 --- a/drivers/net/usb/sierra_net.c +++ b/drivers/net/usb/sierra_net.c @@ -21,8 +21,7 @@ * 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 + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ #define DRIVER_VERSION "v.2.0" diff --git a/drivers/net/usb/smsc75xx.c b/drivers/net/usb/smsc75xx.c index 66ebbacf066f..d9e7892262fa 100644 --- a/drivers/net/usb/smsc75xx.c +++ b/drivers/net/usb/smsc75xx.c @@ -13,14 +13,12 @@ * 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. + * along with this program; if not, see <http://www.gnu.org/licenses/>. * *****************************************************************************/ #include <linux/module.h> #include <linux/kmod.h> -#include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> @@ -2108,6 +2106,10 @@ static void smsc75xx_rx_csum_offload(struct usbnet *dev, struct sk_buff *skb, static int smsc75xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + while (skb->len > 0) { u32 rx_cmd_a, rx_cmd_b, align_count, size; struct sk_buff *ax_skb; diff --git a/drivers/net/usb/smsc75xx.h b/drivers/net/usb/smsc75xx.h index 67eba39e6ee2..2c7ea8fd184f 100644 --- a/drivers/net/usb/smsc75xx.h +++ b/drivers/net/usb/smsc75xx.h @@ -13,8 +13,7 @@ * 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. + * along with this program; if not, see <http://www.gnu.org/licenses/>. * *****************************************************************************/ diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 3f38ba868f61..424db65e4396 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -13,14 +13,12 @@ * 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. + * along with this program; if not, see <http://www.gnu.org/licenses/>. * *****************************************************************************/ #include <linux/module.h> #include <linux/kmod.h> -#include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> @@ -1725,6 +1723,10 @@ static void smsc95xx_rx_csum_offload(struct sk_buff *skb) static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) { + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + while (skb->len > 0) { u32 header, align_count; struct sk_buff *ax_skb; diff --git a/drivers/net/usb/smsc95xx.h b/drivers/net/usb/smsc95xx.h index f360ee372554..526faa0c44e6 100644 --- a/drivers/net/usb/smsc95xx.h +++ b/drivers/net/usb/smsc95xx.h @@ -13,8 +13,7 @@ * 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. + * along with this program; if not, see <http://www.gnu.org/licenses/>. * *****************************************************************************/ diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c index 7ec3e0ee0783..99b69af14274 100644 --- a/drivers/net/usb/sr9700.c +++ b/drivers/net/usb/sr9700.c @@ -13,7 +13,6 @@ #include <linux/module.h> #include <linux/sched.h> #include <linux/stddef.h> -#include <linux/init.h> #include <linux/netdevice.h> #include <linux/etherdevice.h> #include <linux/ethtool.h> diff --git a/drivers/net/usb/sr9800.c b/drivers/net/usb/sr9800.c new file mode 100644 index 000000000000..b94a0fbb8b3b --- /dev/null +++ b/drivers/net/usb/sr9800.c @@ -0,0 +1,874 @@ +/* CoreChip-sz SR9800 one chip USB 2.0 Ethernet Devices + * + * Author : Liu Junliang <liujunliang_ljl@163.com> + * + * Based on asix_common.c, asix_devices.c + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied.* + */ + +#include <linux/module.h> +#include <linux/kmod.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/usb/usbnet.h> +#include <linux/slab.h> +#include <linux/if_vlan.h> + +#include "sr9800.h" + +static int sr_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data) +{ + int err; + + err = usbnet_read_cmd(dev, cmd, SR_REQ_RD_REG, value, index, + data, size); + if ((err != size) && (err >= 0)) + err = -EINVAL; + + return err; +} + +static int sr_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data) +{ + int err; + + err = usbnet_write_cmd(dev, cmd, SR_REQ_WR_REG, value, index, + data, size); + if ((err != size) && (err >= 0)) + err = -EINVAL; + + return err; +} + +static void +sr_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index, + u16 size, void *data) +{ + usbnet_write_cmd_async(dev, cmd, SR_REQ_WR_REG, value, index, data, + size); +} + +static int sr_rx_fixup(struct usbnet *dev, struct sk_buff *skb) +{ + int offset = 0; + + /* This check is no longer done by usbnet */ + if (skb->len < dev->net->hard_header_len) + return 0; + + while (offset + sizeof(u32) < skb->len) { + struct sk_buff *sr_skb; + u16 size; + u32 header = get_unaligned_le32(skb->data + offset); + + offset += sizeof(u32); + /* get the packet length */ + size = (u16) (header & 0x7ff); + if (size != ((~header >> 16) & 0x07ff)) { + netdev_err(dev->net, "%s : Bad Header Length\n", + __func__); + return 0; + } + + if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) || + (size + offset > skb->len)) { + netdev_err(dev->net, "%s : Bad RX Length %d\n", + __func__, size); + return 0; + } + sr_skb = netdev_alloc_skb_ip_align(dev->net, size); + if (!sr_skb) + return 0; + + skb_put(sr_skb, size); + memcpy(sr_skb->data, skb->data + offset, size); + usbnet_skb_return(dev, sr_skb); + + offset += (size + 1) & 0xfffe; + } + + if (skb->len != offset) { + netdev_err(dev->net, "%s : Bad SKB Length %d\n", __func__, + skb->len); + return 0; + } + + return 1; +} + +static struct sk_buff *sr_tx_fixup(struct usbnet *dev, struct sk_buff *skb, + gfp_t flags) +{ + int headroom = skb_headroom(skb); + int tailroom = skb_tailroom(skb); + u32 padbytes = 0xffff0000; + u32 packet_len; + int padlen; + + padlen = ((skb->len + 4) % (dev->maxpacket - 1)) ? 0 : 4; + + if ((!skb_cloned(skb)) && ((headroom + tailroom) >= (4 + padlen))) { + if ((headroom < 4) || (tailroom < padlen)) { + skb->data = memmove(skb->head + 4, skb->data, + skb->len); + skb_set_tail_pointer(skb, skb->len); + } + } else { + struct sk_buff *skb2; + skb2 = skb_copy_expand(skb, 4, padlen, flags); + dev_kfree_skb_any(skb); + skb = skb2; + if (!skb) + return NULL; + } + + skb_push(skb, 4); + packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4); + cpu_to_le32s(&packet_len); + skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len)); + + if (padlen) { + cpu_to_le32s(&padbytes); + memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes)); + skb_put(skb, sizeof(padbytes)); + } + + return skb; +} + +static void sr_status(struct usbnet *dev, struct urb *urb) +{ + struct sr9800_int_data *event; + int link; + + if (urb->actual_length < 8) + return; + + event = urb->transfer_buffer; + link = event->link & 0x01; + if (netif_carrier_ok(dev->net) != link) { + usbnet_link_change(dev, link, 1); + netdev_dbg(dev->net, "Link Status is: %d\n", link); + } + + return; +} + +static inline int sr_set_sw_mii(struct usbnet *dev) +{ + int ret; + + ret = sr_write_cmd(dev, SR_CMD_SET_SW_MII, 0x0000, 0, 0, NULL); + if (ret < 0) + netdev_err(dev->net, "Failed to enable software MII access\n"); + return ret; +} + +static inline int sr_set_hw_mii(struct usbnet *dev) +{ + int ret; + + ret = sr_write_cmd(dev, SR_CMD_SET_HW_MII, 0x0000, 0, 0, NULL); + if (ret < 0) + netdev_err(dev->net, "Failed to enable hardware MII access\n"); + return ret; +} + +static inline int sr_get_phy_addr(struct usbnet *dev) +{ + u8 buf[2]; + int ret; + + ret = sr_read_cmd(dev, SR_CMD_READ_PHY_ID, 0, 0, 2, buf); + if (ret < 0) { + netdev_err(dev->net, "%s : Error reading PHYID register:%02x\n", + __func__, ret); + goto out; + } + netdev_dbg(dev->net, "%s : returning 0x%04x\n", __func__, + *((__le16 *)buf)); + + ret = buf[1]; + +out: + return ret; +} + +static int sr_sw_reset(struct usbnet *dev, u8 flags) +{ + int ret; + + ret = sr_write_cmd(dev, SR_CMD_SW_RESET, flags, 0, 0, NULL); + if (ret < 0) + netdev_err(dev->net, "Failed to send software reset:%02x\n", + ret); + + return ret; +} + +static u16 sr_read_rx_ctl(struct usbnet *dev) +{ + __le16 v; + int ret; + + ret = sr_read_cmd(dev, SR_CMD_READ_RX_CTL, 0, 0, 2, &v); + if (ret < 0) { + netdev_err(dev->net, "Error reading RX_CTL register:%02x\n", + ret); + goto out; + } + + ret = le16_to_cpu(v); +out: + return ret; +} + +static int sr_write_rx_ctl(struct usbnet *dev, u16 mode) +{ + int ret; + + netdev_dbg(dev->net, "%s : mode = 0x%04x\n", __func__, mode); + ret = sr_write_cmd(dev, SR_CMD_WRITE_RX_CTL, mode, 0, 0, NULL); + if (ret < 0) + netdev_err(dev->net, + "Failed to write RX_CTL mode to 0x%04x:%02x\n", + mode, ret); + + return ret; +} + +static u16 sr_read_medium_status(struct usbnet *dev) +{ + __le16 v; + int ret; + + ret = sr_read_cmd(dev, SR_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v); + if (ret < 0) { + netdev_err(dev->net, + "Error reading Medium Status register:%02x\n", ret); + return ret; /* TODO: callers not checking for error ret */ + } + + return le16_to_cpu(v); +} + +static int sr_write_medium_mode(struct usbnet *dev, u16 mode) +{ + int ret; + + netdev_dbg(dev->net, "%s : mode = 0x%04x\n", __func__, mode); + ret = sr_write_cmd(dev, SR_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL); + if (ret < 0) + netdev_err(dev->net, + "Failed to write Medium Mode mode to 0x%04x:%02x\n", + mode, ret); + return ret; +} + +static int sr_write_gpio(struct usbnet *dev, u16 value, int sleep) +{ + int ret; + + netdev_dbg(dev->net, "%s : value = 0x%04x\n", __func__, value); + ret = sr_write_cmd(dev, SR_CMD_WRITE_GPIOS, value, 0, 0, NULL); + if (ret < 0) + netdev_err(dev->net, "Failed to write GPIO value 0x%04x:%02x\n", + value, ret); + if (sleep) + msleep(sleep); + + return ret; +} + +/* SR9800 have a 16-bit RX_CTL value */ +static void sr_set_multicast(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + struct sr_data *data = (struct sr_data *)&dev->data; + u16 rx_ctl = SR_DEFAULT_RX_CTL; + + if (net->flags & IFF_PROMISC) { + rx_ctl |= SR_RX_CTL_PRO; + } else if (net->flags & IFF_ALLMULTI || + netdev_mc_count(net) > SR_MAX_MCAST) { + rx_ctl |= SR_RX_CTL_AMALL; + } else if (netdev_mc_empty(net)) { + /* 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 + */ + struct netdev_hw_addr *ha; + u32 crc_bits; + + memset(data->multi_filter, 0, SR_MCAST_FILTER_SIZE); + + /* Build the multicast hash filter. */ + netdev_for_each_mc_addr(ha, net) { + crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26; + data->multi_filter[crc_bits >> 3] |= + 1 << (crc_bits & 7); + } + + sr_write_cmd_async(dev, SR_CMD_WRITE_MULTI_FILTER, 0, 0, + SR_MCAST_FILTER_SIZE, data->multi_filter); + + rx_ctl |= SR_RX_CTL_AM; + } + + sr_write_cmd_async(dev, SR_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL); +} + +static int sr_mdio_read(struct net_device *net, int phy_id, int loc) +{ + struct usbnet *dev = netdev_priv(net); + __le16 res; + + mutex_lock(&dev->phy_mutex); + sr_set_sw_mii(dev); + sr_read_cmd(dev, SR_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, &res); + sr_set_hw_mii(dev); + mutex_unlock(&dev->phy_mutex); + + netdev_dbg(dev->net, + "%s : phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n", __func__, + phy_id, loc, le16_to_cpu(res)); + + return le16_to_cpu(res); +} + +static void +sr_mdio_write(struct net_device *net, int phy_id, int loc, int val) +{ + struct usbnet *dev = netdev_priv(net); + __le16 res = cpu_to_le16(val); + + netdev_dbg(dev->net, + "%s : phy_id=0x%02x, loc=0x%02x, val=0x%04x\n", __func__, + phy_id, loc, val); + mutex_lock(&dev->phy_mutex); + sr_set_sw_mii(dev); + sr_write_cmd(dev, SR_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res); + sr_set_hw_mii(dev); + mutex_unlock(&dev->phy_mutex); +} + +/* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */ +static u32 sr_get_phyid(struct usbnet *dev) +{ + int phy_reg; + u32 phy_id; + int i; + + /* Poll for the rare case the FW or phy isn't ready yet. */ + for (i = 0; i < 100; i++) { + phy_reg = sr_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1); + if (phy_reg != 0 && phy_reg != 0xFFFF) + break; + mdelay(1); + } + + if (phy_reg <= 0 || phy_reg == 0xFFFF) + return 0; + + phy_id = (phy_reg & 0xffff) << 16; + + phy_reg = sr_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2); + if (phy_reg < 0) + return 0; + + phy_id |= (phy_reg & 0xffff); + + return phy_id; +} + +static void +sr_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) +{ + struct usbnet *dev = netdev_priv(net); + u8 opt; + + if (sr_read_cmd(dev, SR_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) { + wolinfo->supported = 0; + wolinfo->wolopts = 0; + return; + } + wolinfo->supported = WAKE_PHY | WAKE_MAGIC; + wolinfo->wolopts = 0; + if (opt & SR_MONITOR_LINK) + wolinfo->wolopts |= WAKE_PHY; + if (opt & SR_MONITOR_MAGIC) + wolinfo->wolopts |= WAKE_MAGIC; +} + +static int +sr_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo) +{ + struct usbnet *dev = netdev_priv(net); + u8 opt = 0; + + if (wolinfo->wolopts & WAKE_PHY) + opt |= SR_MONITOR_LINK; + if (wolinfo->wolopts & WAKE_MAGIC) + opt |= SR_MONITOR_MAGIC; + + if (sr_write_cmd(dev, SR_CMD_WRITE_MONITOR_MODE, + opt, 0, 0, NULL) < 0) + return -EINVAL; + + return 0; +} + +static int sr_get_eeprom_len(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + struct sr_data *data = (struct sr_data *)&dev->data; + + return data->eeprom_len; +} + +static int sr_get_eeprom(struct net_device *net, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct usbnet *dev = netdev_priv(net); + __le16 *ebuf = (__le16 *)data; + int ret; + int i; + + /* Crude hack to ensure that we don't overwrite memory + * if an odd length is supplied + */ + if (eeprom->len % 2) + return -EINVAL; + + eeprom->magic = SR_EEPROM_MAGIC; + + /* sr9800 returns 2 bytes from eeprom on read */ + for (i = 0; i < eeprom->len / 2; i++) { + ret = sr_read_cmd(dev, SR_CMD_READ_EEPROM, eeprom->offset + i, + 0, 2, &ebuf[i]); + if (ret < 0) + return -EINVAL; + } + return 0; +} + +static void sr_get_drvinfo(struct net_device *net, + struct ethtool_drvinfo *info) +{ + struct usbnet *dev = netdev_priv(net); + struct sr_data *data = (struct sr_data *)&dev->data; + + /* Inherit standard device info */ + usbnet_get_drvinfo(net, info); + strncpy(info->driver, DRIVER_NAME, sizeof(info->driver)); + strncpy(info->version, DRIVER_VERSION, sizeof(info->version)); + info->eedump_len = data->eeprom_len; +} + +static u32 sr_get_link(struct net_device *net) +{ + struct usbnet *dev = netdev_priv(net); + + return mii_link_ok(&dev->mii); +} + +static int sr_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); +} + +static int sr_set_mac_address(struct net_device *net, void *p) +{ + struct usbnet *dev = netdev_priv(net); + struct sr_data *data = (struct sr_data *)&dev->data; + 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); + + /* We use the 20 byte dev->data + * for our 6 byte mac buffer + * to avoid allocating memory that + * is tricky to free later + */ + memcpy(data->mac_addr, addr->sa_data, ETH_ALEN); + sr_write_cmd_async(dev, SR_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, + data->mac_addr); + + return 0; +} + +static const struct ethtool_ops sr9800_ethtool_ops = { + .get_drvinfo = sr_get_drvinfo, + .get_link = sr_get_link, + .get_msglevel = usbnet_get_msglevel, + .set_msglevel = usbnet_set_msglevel, + .get_wol = sr_get_wol, + .set_wol = sr_set_wol, + .get_eeprom_len = sr_get_eeprom_len, + .get_eeprom = sr_get_eeprom, + .get_settings = usbnet_get_settings, + .set_settings = usbnet_set_settings, + .nway_reset = usbnet_nway_reset, +}; + +static int sr9800_link_reset(struct usbnet *dev) +{ + struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET }; + u16 mode; + + mii_check_media(&dev->mii, 1, 1); + mii_ethtool_gset(&dev->mii, &ecmd); + mode = SR9800_MEDIUM_DEFAULT; + + if (ethtool_cmd_speed(&ecmd) != SPEED_100) + mode &= ~SR_MEDIUM_PS; + + if (ecmd.duplex != DUPLEX_FULL) + mode &= ~SR_MEDIUM_FD; + + netdev_dbg(dev->net, "%s : speed: %u duplex: %d mode: 0x%04x\n", + __func__, ethtool_cmd_speed(&ecmd), ecmd.duplex, mode); + + sr_write_medium_mode(dev, mode); + + return 0; +} + + +static int sr9800_set_default_mode(struct usbnet *dev) +{ + u16 rx_ctl; + int ret; + + sr_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET); + sr_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE, + ADVERTISE_ALL | ADVERTISE_CSMA); + mii_nway_restart(&dev->mii); + + ret = sr_write_medium_mode(dev, SR9800_MEDIUM_DEFAULT); + if (ret < 0) + goto out; + + ret = sr_write_cmd(dev, SR_CMD_WRITE_IPG012, + SR9800_IPG0_DEFAULT | SR9800_IPG1_DEFAULT, + SR9800_IPG2_DEFAULT, 0, NULL); + if (ret < 0) { + netdev_dbg(dev->net, "Write IPG,IPG1,IPG2 failed: %d\n", ret); + goto out; + } + + /* Set RX_CTL to default values with 2k buffer, and enable cactus */ + ret = sr_write_rx_ctl(dev, SR_DEFAULT_RX_CTL); + if (ret < 0) + goto out; + + rx_ctl = sr_read_rx_ctl(dev); + netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations\n", + rx_ctl); + + rx_ctl = sr_read_medium_status(dev); + netdev_dbg(dev->net, "Medium Status:0x%04x after all initializations\n", + rx_ctl); + + return 0; +out: + return ret; +} + +static int sr9800_reset(struct usbnet *dev) +{ + struct sr_data *data = (struct sr_data *)&dev->data; + int ret, embd_phy; + u16 rx_ctl; + + ret = sr_write_gpio(dev, + SR_GPIO_RSE | SR_GPIO_GPO_2 | SR_GPIO_GPO2EN, 5); + if (ret < 0) + goto out; + + embd_phy = ((sr_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0); + + ret = sr_write_cmd(dev, SR_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); + if (ret < 0) { + netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret); + goto out; + } + + ret = sr_sw_reset(dev, SR_SWRESET_IPPD | SR_SWRESET_PRL); + if (ret < 0) + goto out; + + msleep(150); + + ret = sr_sw_reset(dev, SR_SWRESET_CLEAR); + if (ret < 0) + goto out; + + msleep(150); + + if (embd_phy) { + ret = sr_sw_reset(dev, SR_SWRESET_IPRL); + if (ret < 0) + goto out; + } else { + ret = sr_sw_reset(dev, SR_SWRESET_PRTE); + if (ret < 0) + goto out; + } + + msleep(150); + rx_ctl = sr_read_rx_ctl(dev); + netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl); + ret = sr_write_rx_ctl(dev, 0x0000); + if (ret < 0) + goto out; + + rx_ctl = sr_read_rx_ctl(dev); + netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl); + + ret = sr_sw_reset(dev, SR_SWRESET_PRL); + if (ret < 0) + goto out; + + msleep(150); + + ret = sr_sw_reset(dev, SR_SWRESET_IPRL | SR_SWRESET_PRL); + if (ret < 0) + goto out; + + msleep(150); + + ret = sr9800_set_default_mode(dev); + if (ret < 0) + goto out; + + /* Rewrite MAC address */ + memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN); + ret = sr_write_cmd(dev, SR_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN, + data->mac_addr); + if (ret < 0) + goto out; + + return 0; + +out: + return ret; +} + +static const struct net_device_ops sr9800_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 = usbnet_change_mtu, + .ndo_set_mac_address = sr_set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = sr_ioctl, + .ndo_set_rx_mode = sr_set_multicast, +}; + +static int sr9800_phy_powerup(struct usbnet *dev) +{ + int ret; + + /* set the embedded Ethernet PHY in power-down state */ + ret = sr_sw_reset(dev, SR_SWRESET_IPPD | SR_SWRESET_IPRL); + if (ret < 0) { + netdev_err(dev->net, "Failed to power down PHY : %d\n", ret); + return ret; + } + msleep(20); + + /* set the embedded Ethernet PHY in power-up state */ + ret = sr_sw_reset(dev, SR_SWRESET_IPRL); + if (ret < 0) { + netdev_err(dev->net, "Failed to reset PHY: %d\n", ret); + return ret; + } + msleep(600); + + /* set the embedded Ethernet PHY in reset state */ + ret = sr_sw_reset(dev, SR_SWRESET_CLEAR); + if (ret < 0) { + netdev_err(dev->net, "Failed to power up PHY: %d\n", ret); + return ret; + } + msleep(20); + + /* set the embedded Ethernet PHY in power-up state */ + ret = sr_sw_reset(dev, SR_SWRESET_IPRL); + if (ret < 0) { + netdev_err(dev->net, "Failed to reset PHY: %d\n", ret); + return ret; + } + + return 0; +} + +static int sr9800_bind(struct usbnet *dev, struct usb_interface *intf) +{ + struct sr_data *data = (struct sr_data *)&dev->data; + u16 led01_mux, led23_mux; + int ret, embd_phy; + u32 phyid; + u16 rx_ctl; + + data->eeprom_len = SR9800_EEPROM_LEN; + + usbnet_get_endpoints(dev, intf); + + /* LED Setting Rule : + * AABB:CCDD + * AA : MFA0(LED0) + * BB : MFA1(LED1) + * CC : MFA2(LED2), Reserved for SR9800 + * DD : MFA3(LED3), Reserved for SR9800 + */ + led01_mux = (SR_LED_MUX_LINK_ACTIVE << 8) | SR_LED_MUX_LINK; + led23_mux = (SR_LED_MUX_LINK_ACTIVE << 8) | SR_LED_MUX_TX_ACTIVE; + ret = sr_write_cmd(dev, SR_CMD_LED_MUX, led01_mux, led23_mux, 0, NULL); + if (ret < 0) { + netdev_err(dev->net, "set LINK LED failed : %d\n", ret); + goto out; + } + + /* Get the MAC address */ + ret = sr_read_cmd(dev, SR_CMD_READ_NODE_ID, 0, 0, ETH_ALEN, + dev->net->dev_addr); + if (ret < 0) { + netdev_dbg(dev->net, "Failed to read MAC address: %d\n", ret); + return ret; + } + netdev_dbg(dev->net, "mac addr : %pM\n", dev->net->dev_addr); + + /* Initialize MII structure */ + dev->mii.dev = dev->net; + dev->mii.mdio_read = sr_mdio_read; + dev->mii.mdio_write = sr_mdio_write; + dev->mii.phy_id_mask = 0x1f; + dev->mii.reg_num_mask = 0x1f; + dev->mii.phy_id = sr_get_phy_addr(dev); + + dev->net->netdev_ops = &sr9800_netdev_ops; + dev->net->ethtool_ops = &sr9800_ethtool_ops; + + embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0); + /* Reset the PHY to normal operation mode */ + ret = sr_write_cmd(dev, SR_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL); + if (ret < 0) { + netdev_dbg(dev->net, "Select PHY #1 failed: %d\n", ret); + return ret; + } + + /* Init PHY routine */ + ret = sr9800_phy_powerup(dev); + if (ret < 0) + goto out; + + rx_ctl = sr_read_rx_ctl(dev); + netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset\n", rx_ctl); + ret = sr_write_rx_ctl(dev, 0x0000); + if (ret < 0) + goto out; + + rx_ctl = sr_read_rx_ctl(dev); + netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000\n", rx_ctl); + + /* Read PHYID register *AFTER* the PHY was reset properly */ + phyid = sr_get_phyid(dev); + netdev_dbg(dev->net, "PHYID=0x%08x\n", phyid); + + /* medium mode setting */ + ret = sr9800_set_default_mode(dev); + if (ret < 0) + goto out; + + if (dev->udev->speed == USB_SPEED_HIGH) { + ret = sr_write_cmd(dev, SR_CMD_BULKIN_SIZE, + SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].byte_cnt, + SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].threshold, + 0, NULL); + if (ret < 0) { + netdev_err(dev->net, "Reset RX_CTL failed: %d\n", ret); + goto out; + } + dev->rx_urb_size = + SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].size; + } else { + ret = sr_write_cmd(dev, SR_CMD_BULKIN_SIZE, + SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].byte_cnt, + SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].threshold, + 0, NULL); + if (ret < 0) { + netdev_err(dev->net, "Reset RX_CTL failed: %d\n", ret); + goto out; + } + dev->rx_urb_size = + SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].size; + } + netdev_dbg(dev->net, "%s : setting rx_urb_size with : %zu\n", __func__, + dev->rx_urb_size); + return 0; + +out: + return ret; +} + +static const struct driver_info sr9800_driver_info = { + .description = "CoreChip SR9800 USB 2.0 Ethernet", + .bind = sr9800_bind, + .status = sr_status, + .link_reset = sr9800_link_reset, + .reset = sr9800_reset, + .flags = DRIVER_FLAG, + .rx_fixup = sr_rx_fixup, + .tx_fixup = sr_tx_fixup, +}; + +static const struct usb_device_id products[] = { + { + USB_DEVICE(0x0fe6, 0x9800), /* SR9800 Device */ + .driver_info = (unsigned long) &sr9800_driver_info, + }, + {}, /* END */ +}; + +MODULE_DEVICE_TABLE(usb, products); + +static struct usb_driver sr_driver = { + .name = DRIVER_NAME, + .id_table = products, + .probe = usbnet_probe, + .suspend = usbnet_suspend, + .resume = usbnet_resume, + .disconnect = usbnet_disconnect, + .supports_autosuspend = 1, +}; + +module_usb_driver(sr_driver); + +MODULE_AUTHOR("Liu Junliang <liujunliang_ljl@163.com"); +MODULE_VERSION(DRIVER_VERSION); +MODULE_DESCRIPTION("SR9800 USB 2.0 USB2NET Dev : http://www.corechip-sz.com"); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/usb/sr9800.h b/drivers/net/usb/sr9800.h new file mode 100644 index 000000000000..18f670251275 --- /dev/null +++ b/drivers/net/usb/sr9800.h @@ -0,0 +1,202 @@ +/* CoreChip-sz SR9800 one chip USB 2.0 Ethernet Devices + * + * Author : Liu Junliang <liujunliang_ljl@163.com> + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef _SR9800_H +#define _SR9800_H + +/* SR9800 spec. command table on Linux Platform */ + +/* command : Software Station Management Control Reg */ +#define SR_CMD_SET_SW_MII 0x06 +/* command : PHY Read Reg */ +#define SR_CMD_READ_MII_REG 0x07 +/* command : PHY Write Reg */ +#define SR_CMD_WRITE_MII_REG 0x08 +/* command : Hardware Station Management Control Reg */ +#define SR_CMD_SET_HW_MII 0x0a +/* command : SROM Read Reg */ +#define SR_CMD_READ_EEPROM 0x0b +/* command : SROM Write Reg */ +#define SR_CMD_WRITE_EEPROM 0x0c +/* command : SROM Write Enable Reg */ +#define SR_CMD_WRITE_ENABLE 0x0d +/* command : SROM Write Disable Reg */ +#define SR_CMD_WRITE_DISABLE 0x0e +/* command : RX Control Read Reg */ +#define SR_CMD_READ_RX_CTL 0x0f +#define SR_RX_CTL_PRO (1 << 0) +#define SR_RX_CTL_AMALL (1 << 1) +#define SR_RX_CTL_SEP (1 << 2) +#define SR_RX_CTL_AB (1 << 3) +#define SR_RX_CTL_AM (1 << 4) +#define SR_RX_CTL_AP (1 << 5) +#define SR_RX_CTL_ARP (1 << 6) +#define SR_RX_CTL_SO (1 << 7) +#define SR_RX_CTL_RH1M (1 << 8) +#define SR_RX_CTL_RH2M (1 << 9) +#define SR_RX_CTL_RH3M (1 << 10) +/* command : RX Control Write Reg */ +#define SR_CMD_WRITE_RX_CTL 0x10 +/* command : IPG0/IPG1/IPG2 Control Read Reg */ +#define SR_CMD_READ_IPG012 0x11 +/* command : IPG0/IPG1/IPG2 Control Write Reg */ +#define SR_CMD_WRITE_IPG012 0x12 +/* command : Node ID Read Reg */ +#define SR_CMD_READ_NODE_ID 0x13 +/* command : Node ID Write Reg */ +#define SR_CMD_WRITE_NODE_ID 0x14 +/* command : Multicast Filter Array Read Reg */ +#define SR_CMD_READ_MULTI_FILTER 0x15 +/* command : Multicast Filter Array Write Reg */ +#define SR_CMD_WRITE_MULTI_FILTER 0x16 +/* command : Eth/HomePNA PHY Address Reg */ +#define SR_CMD_READ_PHY_ID 0x19 +/* command : Medium Status Read Reg */ +#define SR_CMD_READ_MEDIUM_STATUS 0x1a +#define SR_MONITOR_LINK (1 << 1) +#define SR_MONITOR_MAGIC (1 << 2) +#define SR_MONITOR_HSFS (1 << 4) +/* command : Medium Status Write Reg */ +#define SR_CMD_WRITE_MEDIUM_MODE 0x1b +#define SR_MEDIUM_GM (1 << 0) +#define SR_MEDIUM_FD (1 << 1) +#define SR_MEDIUM_AC (1 << 2) +#define SR_MEDIUM_ENCK (1 << 3) +#define SR_MEDIUM_RFC (1 << 4) +#define SR_MEDIUM_TFC (1 << 5) +#define SR_MEDIUM_JFE (1 << 6) +#define SR_MEDIUM_PF (1 << 7) +#define SR_MEDIUM_RE (1 << 8) +#define SR_MEDIUM_PS (1 << 9) +#define SR_MEDIUM_RSV (1 << 10) +#define SR_MEDIUM_SBP (1 << 11) +#define SR_MEDIUM_SM (1 << 12) +/* command : Monitor Mode Status Read Reg */ +#define SR_CMD_READ_MONITOR_MODE 0x1c +/* command : Monitor Mode Status Write Reg */ +#define SR_CMD_WRITE_MONITOR_MODE 0x1d +/* command : GPIO Status Read Reg */ +#define SR_CMD_READ_GPIOS 0x1e +#define SR_GPIO_GPO0EN (1 << 0) /* GPIO0 Output enable */ +#define SR_GPIO_GPO_0 (1 << 1) /* GPIO0 Output value */ +#define SR_GPIO_GPO1EN (1 << 2) /* GPIO1 Output enable */ +#define SR_GPIO_GPO_1 (1 << 3) /* GPIO1 Output value */ +#define SR_GPIO_GPO2EN (1 << 4) /* GPIO2 Output enable */ +#define SR_GPIO_GPO_2 (1 << 5) /* GPIO2 Output value */ +#define SR_GPIO_RESERVED (1 << 6) /* Reserved */ +#define SR_GPIO_RSE (1 << 7) /* Reload serial EEPROM */ +/* command : GPIO Status Write Reg */ +#define SR_CMD_WRITE_GPIOS 0x1f +/* command : Eth PHY Power and Reset Control Reg */ +#define SR_CMD_SW_RESET 0x20 +#define SR_SWRESET_CLEAR 0x00 +#define SR_SWRESET_RR (1 << 0) +#define SR_SWRESET_RT (1 << 1) +#define SR_SWRESET_PRTE (1 << 2) +#define SR_SWRESET_PRL (1 << 3) +#define SR_SWRESET_BZ (1 << 4) +#define SR_SWRESET_IPRL (1 << 5) +#define SR_SWRESET_IPPD (1 << 6) +/* command : Software Interface Selection Status Read Reg */ +#define SR_CMD_SW_PHY_STATUS 0x21 +/* command : Software Interface Selection Status Write Reg */ +#define SR_CMD_SW_PHY_SELECT 0x22 +/* command : BULK in Buffer Size Reg */ +#define SR_CMD_BULKIN_SIZE 0x2A +/* command : LED_MUX Control Reg */ +#define SR_CMD_LED_MUX 0x70 +#define SR_LED_MUX_TX_ACTIVE (1 << 0) +#define SR_LED_MUX_RX_ACTIVE (1 << 1) +#define SR_LED_MUX_COLLISION (1 << 2) +#define SR_LED_MUX_DUP_COL (1 << 3) +#define SR_LED_MUX_DUP (1 << 4) +#define SR_LED_MUX_SPEED (1 << 5) +#define SR_LED_MUX_LINK_ACTIVE (1 << 6) +#define SR_LED_MUX_LINK (1 << 7) + +/* Register Access Flags */ +#define SR_REQ_RD_REG (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE) +#define SR_REQ_WR_REG (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE) + +/* Multicast Filter Array size & Max Number */ +#define SR_MCAST_FILTER_SIZE 8 +#define SR_MAX_MCAST 64 + +/* IPG0/1/2 Default Value */ +#define SR9800_IPG0_DEFAULT 0x15 +#define SR9800_IPG1_DEFAULT 0x0c +#define SR9800_IPG2_DEFAULT 0x12 + +/* Medium Status Default Mode */ +#define SR9800_MEDIUM_DEFAULT \ + (SR_MEDIUM_FD | SR_MEDIUM_RFC | \ + SR_MEDIUM_TFC | SR_MEDIUM_PS | \ + SR_MEDIUM_AC | SR_MEDIUM_RE) + +/* RX Control Default Setting */ +#define SR_DEFAULT_RX_CTL \ + (SR_RX_CTL_SO | SR_RX_CTL_AB | SR_RX_CTL_RH1M) + +/* EEPROM Magic Number & EEPROM Size */ +#define SR_EEPROM_MAGIC 0xdeadbeef +#define SR9800_EEPROM_LEN 0xff + +/* SR9800 Driver Version and Driver Name */ +#define DRIVER_VERSION "11-Nov-2013" +#define DRIVER_NAME "CoreChips" +#define DRIVER_FLAG \ + (FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET) + +/* SR9800 BULKIN Buffer Size */ +#define SR9800_MAX_BULKIN_2K 0 +#define SR9800_MAX_BULKIN_4K 1 +#define SR9800_MAX_BULKIN_6K 2 +#define SR9800_MAX_BULKIN_8K 3 +#define SR9800_MAX_BULKIN_16K 4 +#define SR9800_MAX_BULKIN_20K 5 +#define SR9800_MAX_BULKIN_24K 6 +#define SR9800_MAX_BULKIN_32K 7 + +struct {unsigned short size, byte_cnt, threshold; } SR9800_BULKIN_SIZE[] = { + /* 2k */ + {2048, 0x8000, 0x8001}, + /* 4k */ + {4096, 0x8100, 0x8147}, + /* 6k */ + {6144, 0x8200, 0x81EB}, + /* 8k */ + {8192, 0x8300, 0x83D7}, + /* 16 */ + {16384, 0x8400, 0x851E}, + /* 20k */ + {20480, 0x8500, 0x8666}, + /* 24k */ + {24576, 0x8600, 0x87AE}, + /* 32k */ + {32768, 0x8700, 0x8A3D}, +}; + +/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */ +struct sr_data { + u8 multi_filter[SR_MCAST_FILTER_SIZE]; + u8 mac_addr[ETH_ALEN]; + u8 phymode; + u8 ledmode; + u8 eeprom_len; +}; + +struct sr9800_int_data { + __le16 res1; + u8 link; + __le16 res2; + u8 status; + __le16 res3; +} __packed; + +#endif /* _SR9800_H */ diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 8494bb53ebdc..dd10d5817d2a 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -14,8 +14,7 @@ * 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 + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ /* @@ -543,17 +542,19 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb) } // else network stack removes extra byte if we forced a short packet - if (skb->len) { - /* all data was already cloned from skb inside the driver */ - if (dev->driver_info->flags & FLAG_MULTI_PACKET) - dev_kfree_skb_any(skb); - else - usbnet_skb_return(dev, skb); + /* all data was already cloned from skb inside the driver */ + if (dev->driver_info->flags & FLAG_MULTI_PACKET) + goto done; + + if (skb->len < ETH_HLEN) { + dev->net->stats.rx_errors++; + dev->net->stats.rx_length_errors++; + netif_dbg(dev, rx_err, dev->net, "rx length %d\n", skb->len); + } else { + usbnet_skb_return(dev, skb); return; } - netif_dbg(dev, rx_err, dev->net, "drop\n"); - dev->net->stats.rx_errors++; done: skb_queue_tail(&dev->done, skb); } @@ -575,13 +576,6 @@ static void rx_complete (struct urb *urb) switch (urb_status) { /* success */ case 0: - if (skb->len < dev->net->hard_header_len) { - state = rx_cleanup; - dev->net->stats.rx_errors++; - dev->net->stats.rx_length_errors++; - netif_dbg(dev, rx_err, dev->net, - "rx length %d\n", skb->len); - } break; /* stalls need manual reset. this is rare ... except that @@ -1245,7 +1239,7 @@ static int build_dma_sg(const struct sk_buff *skb, struct urb *urb) return -ENOMEM; urb->num_sgs = num_sgs; - sg_init_table(urb->sg, urb->num_sgs); + sg_init_table(urb->sg, urb->num_sgs + 1); sg_set_buf(&urb->sg[s++], skb->data, skb_headlen(skb)); total_len += skb_headlen(skb); diff --git a/drivers/net/usb/zaurus.c b/drivers/net/usb/zaurus.c index 35c90307d473..6aaa6eb9df72 100644 --- a/drivers/net/usb/zaurus.c +++ b/drivers/net/usb/zaurus.c @@ -13,15 +13,13 @@ * 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 + * along with this program; if not, see <http://www.gnu.org/licenses/>. */ // #define DEBUG // error path messages, extra info // #define VERBOSE // more; success messages #include <linux/module.h> -#include <linux/init.h> #include <linux/netdevice.h> #include <linux/ethtool.h> #include <linux/workqueue.h> |