Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 340521
b: refs/heads/master
c: bbd9f9e
h: refs/heads/master
i:
  340519: f2475d9
v: v3
  • Loading branch information
Steve Glendinning authored and David S. Miller committed Oct 31, 2012
1 parent 0d4c891 commit 9e8e644
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 7 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9ecd1c3d6cff05fcfd11517341cc22f61651ec3e
refs/heads/master: bbd9f9ee69242f23c6063f0102bbb98f5bd23521
2 changes: 2 additions & 0 deletions trunk/drivers/net/usb/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ config USB_NET_SMSC75XX
config USB_NET_SMSC95XX
tristate "SMSC LAN95XX based USB 2.0 10/100 ethernet devices"
depends on USB_USBNET
select BITREVERSE
select CRC16
select CRC32
help
This option adds support for SMSC LAN95XX based USB 2.0
Expand Down
127 changes: 121 additions & 6 deletions trunk/drivers/net/usb/smsc95xx.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
#include <linux/ethtool.h>
#include <linux/mii.h>
#include <linux/usb.h>
#include <linux/bitrev.h>
#include <linux/crc16.h>
#include <linux/crc32.h>
#include <linux/usb/usbnet.h>
#include <linux/slab.h>
Expand All @@ -46,7 +48,8 @@
#define SMSC95XX_INTERNAL_PHY_ID (1)
#define SMSC95XX_TX_OVERHEAD (8)
#define SMSC95XX_TX_OVERHEAD_CSUM (12)
#define SUPPORTED_WAKE (WAKE_MAGIC)
#define SUPPORTED_WAKE (WAKE_UCAST | WAKE_BCAST | \
WAKE_MCAST | WAKE_ARP | WAKE_MAGIC)

#define check_warn(ret, fmt, args...) \
({ if (ret < 0) netdev_warn(dev->net, fmt, ##args); })
Expand All @@ -63,6 +66,7 @@ struct smsc95xx_priv {
u32 hash_lo;
u32 wolopts;
spinlock_t mac_cr_lock;
int wuff_filter_count;
};

static bool turbo_mode = true;
Expand Down Expand Up @@ -956,6 +960,7 @@ static const struct net_device_ops smsc95xx_netdev_ops = {
static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
{
struct smsc95xx_priv *pdata = NULL;
u32 val;
int ret;

printk(KERN_INFO SMSC_CHIPNAME " v" SMSC_DRIVER_VERSION "\n");
Expand Down Expand Up @@ -986,6 +991,15 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
/* Init all registers */
ret = smsc95xx_reset(dev);

/* detect device revision as different features may be available */
ret = smsc95xx_read_reg(dev, ID_REV, &val);
check_warn_return(ret, "Failed to read ID_REV: %d\n", ret);
val >>= 16;
if ((val == ID_REV_CHIP_ID_9500A_) || (val == ID_REV_CHIP_ID_9512_))
pdata->wuff_filter_count = LAN9500A_WUFF_NUM;
else
pdata->wuff_filter_count = LAN9500_WUFF_NUM;

dev->net->netdev_ops = &smsc95xx_netdev_ops;
dev->net->ethtool_ops = &smsc95xx_ethtool_ops;
dev->net->flags |= IFF_MULTICAST;
Expand All @@ -1005,6 +1019,11 @@ static void smsc95xx_unbind(struct usbnet *dev, struct usb_interface *intf)
}
}

static u16 smsc_crc(const u8 *buffer, size_t len, int filter)
{
return bitrev16(crc16(0xFFFF, buffer, len)) << ((filter % 2) * 16);
}

static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
{
struct usbnet *dev = usb_get_intfdata(intf);
Expand Down Expand Up @@ -1049,6 +1068,94 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
return 0;
}

if (pdata->wolopts & (WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_UCAST)) {
u32 *filter_mask = kzalloc(32, GFP_KERNEL);
u32 *command = kzalloc(2, GFP_KERNEL);
u32 *offset = kzalloc(2, GFP_KERNEL);
u32 *crc = kzalloc(4, GFP_KERNEL);
int i, filter = 0;

if (pdata->wolopts & WAKE_BCAST) {
const u8 bcast[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
netdev_info(dev->net, "enabling broadcast detection");
filter_mask[filter * 4] = 0x003F;
filter_mask[filter * 4 + 1] = 0x00;
filter_mask[filter * 4 + 2] = 0x00;
filter_mask[filter * 4 + 3] = 0x00;
command[filter/4] |= 0x05UL << ((filter % 4) * 8);
offset[filter/4] |= 0x00 << ((filter % 4) * 8);
crc[filter/2] |= smsc_crc(bcast, 6, filter);
filter++;
}

if (pdata->wolopts & WAKE_MCAST) {
const u8 mcast[] = {0x01, 0x00, 0x5E};
netdev_info(dev->net, "enabling multicast detection");
filter_mask[filter * 4] = 0x0007;
filter_mask[filter * 4 + 1] = 0x00;
filter_mask[filter * 4 + 2] = 0x00;
filter_mask[filter * 4 + 3] = 0x00;
command[filter/4] |= 0x09UL << ((filter % 4) * 8);
offset[filter/4] |= 0x00 << ((filter % 4) * 8);
crc[filter/2] |= smsc_crc(mcast, 3, filter);
filter++;
}

if (pdata->wolopts & WAKE_ARP) {
const u8 arp[] = {0x08, 0x06};
netdev_info(dev->net, "enabling ARP detection");
filter_mask[filter * 4] = 0x0003;
filter_mask[filter * 4 + 1] = 0x00;
filter_mask[filter * 4 + 2] = 0x00;
filter_mask[filter * 4 + 3] = 0x00;
command[filter/4] |= 0x05UL << ((filter % 4) * 8);
offset[filter/4] |= 0x0C << ((filter % 4) * 8);
crc[filter/2] |= smsc_crc(arp, 2, filter);
filter++;
}

if (pdata->wolopts & WAKE_UCAST) {
netdev_info(dev->net, "enabling unicast detection");
filter_mask[filter * 4] = 0x003F;
filter_mask[filter * 4 + 1] = 0x00;
filter_mask[filter * 4 + 2] = 0x00;
filter_mask[filter * 4 + 3] = 0x00;
command[filter/4] |= 0x01UL << ((filter % 4) * 8);
offset[filter/4] |= 0x00 << ((filter % 4) * 8);
crc[filter/2] |= smsc_crc(dev->net->dev_addr, ETH_ALEN, filter);
filter++;
}

for (i = 0; i < (pdata->wuff_filter_count * 4); i++) {
ret = smsc95xx_write_reg(dev, WUFF, filter_mask[i]);
check_warn_return(ret, "Error writing WUFF");
}

for (i = 0; i < (pdata->wuff_filter_count / 4); i++) {
ret = smsc95xx_write_reg(dev, WUFF, command[i]);
check_warn_return(ret, "Error writing WUFF");
}

for (i = 0; i < (pdata->wuff_filter_count / 4); i++) {
ret = smsc95xx_write_reg(dev, WUFF, offset[i]);
check_warn_return(ret, "Error writing WUFF");
}

for (i = 0; i < (pdata->wuff_filter_count / 2); i++) {
ret = smsc95xx_write_reg(dev, WUFF, crc[i]);
check_warn_return(ret, "Error writing WUFF");
}

/* clear any pending pattern match packet status */
ret = smsc95xx_read_reg(dev, WUCSR, &val);
check_warn_return(ret, "Error reading WUCSR");

val |= WUCSR_WUFR_;

ret = smsc95xx_write_reg(dev, WUCSR, val);
check_warn_return(ret, "Error writing WUCSR");
}

if (pdata->wolopts & WAKE_MAGIC) {
/* clear any pending magic packet status */
ret = smsc95xx_read_reg(dev, WUCSR, &val);
Expand All @@ -1060,10 +1167,18 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
check_warn_return(ret, "Error writing WUCSR");
}

/* enable/disable magic packup wake */
/* enable/disable wakeup sources */
ret = smsc95xx_read_reg(dev, WUCSR, &val);
check_warn_return(ret, "Error reading WUCSR");

if (pdata->wolopts & (WAKE_BCAST | WAKE_MCAST | WAKE_ARP | WAKE_UCAST)) {
netdev_info(dev->net, "enabling pattern match wakeup");
val |= WUCSR_WAKE_EN_;
} else {
netdev_info(dev->net, "disabling pattern match wakeup");
val &= ~WUCSR_WAKE_EN_;
}

if (pdata->wolopts & WAKE_MAGIC) {
netdev_info(dev->net, "enabling magic packet wakeup");
val |= WUCSR_MPEN_;
Expand All @@ -1084,7 +1199,7 @@ static int smsc95xx_suspend(struct usb_interface *intf, pm_message_t message)
ret = smsc95xx_write_reg(dev, PM_CTRL, val);
check_warn_return(ret, "Error writing PM_CTRL");

/* enable receiver */
/* enable receiver to enable frame reception */
smsc95xx_start_rx_path(dev);

/* some wol options are enabled, so enter SUSPEND0 */
Expand Down Expand Up @@ -1123,14 +1238,14 @@ static int smsc95xx_resume(struct usb_interface *intf)

BUG_ON(!dev);

if (pdata->wolopts & WAKE_MAGIC) {
if (pdata->wolopts) {
smsc95xx_clear_feature(dev, USB_DEVICE_REMOTE_WAKEUP);

/* Disable magic packup wake */
/* clear wake-up sources */
ret = smsc95xx_read_reg(dev, WUCSR, &val);
check_warn_return(ret, "Error reading WUCSR");

val &= ~WUCSR_MPEN_;
val &= ~(WUCSR_WAKE_EN_ | WUCSR_MPEN_);

ret = smsc95xx_write_reg(dev, WUCSR, val);
check_warn_return(ret, "Error writing WUCSR");
Expand Down
5 changes: 5 additions & 0 deletions trunk/drivers/net/usb/smsc95xx.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
#define ID_REV_CHIP_ID_MASK_ (0xFFFF0000)
#define ID_REV_CHIP_REV_MASK_ (0x0000FFFF)
#define ID_REV_CHIP_ID_9500_ (0x9500)
#define ID_REV_CHIP_ID_9500A_ (0x9E00)
#define ID_REV_CHIP_ID_9512_ (0xEC00)

#define INT_STS (0x08)
#define INT_STS_TX_STOP_ (0x00020000)
Expand Down Expand Up @@ -203,8 +205,11 @@
#define VLAN2 (0x124)

#define WUFF (0x128)
#define LAN9500_WUFF_NUM (4)
#define LAN9500A_WUFF_NUM (8)

#define WUCSR (0x12C)
#define WUCSR_WFF_PTR_RST_ (0x80000000)
#define WUCSR_GUE_ (0x00000200)
#define WUCSR_WUFR_ (0x00000040)
#define WUCSR_MPR_ (0x00000020)
Expand Down

0 comments on commit 9e8e644

Please sign in to comment.