[PATCH] b44: add wol for old nic
This patch adds wol support for the older 440x nics that use pattern matching. This patch is a redo thanks to feedback from Michael Chan and Francois Romieu. Signed-off-by: Gary Zambrano <zambrano@broadcom.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
This commit is contained in:
parent
00e8b3aa1c
commit
725ad800b7
2 changed files with 112 additions and 1 deletions
|
@ -75,6 +75,15 @@
|
||||||
/* minimum number of free TX descriptors required to wake up TX process */
|
/* minimum number of free TX descriptors required to wake up TX process */
|
||||||
#define B44_TX_WAKEUP_THRESH (B44_TX_RING_SIZE / 4)
|
#define B44_TX_WAKEUP_THRESH (B44_TX_RING_SIZE / 4)
|
||||||
|
|
||||||
|
/* b44 internal pattern match filter info */
|
||||||
|
#define B44_PATTERN_BASE 0x400
|
||||||
|
#define B44_PATTERN_SIZE 0x80
|
||||||
|
#define B44_PMASK_BASE 0x600
|
||||||
|
#define B44_PMASK_SIZE 0x10
|
||||||
|
#define B44_MAX_PATTERNS 16
|
||||||
|
#define B44_ETHIPV6UDP_HLEN 62
|
||||||
|
#define B44_ETHIPV4UDP_HLEN 42
|
||||||
|
|
||||||
static char version[] __devinitdata =
|
static char version[] __devinitdata =
|
||||||
DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
|
DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
|
||||||
|
|
||||||
|
@ -1457,6 +1466,103 @@ static void b44_poll_controller(struct net_device *dev)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void bwfilter_table(struct b44 *bp, u8 *pp, u32 bytes, u32 table_offset)
|
||||||
|
{
|
||||||
|
u32 i;
|
||||||
|
u32 *pattern = (u32 *) pp;
|
||||||
|
|
||||||
|
for (i = 0; i < bytes; i += sizeof(u32)) {
|
||||||
|
bw32(bp, B44_FILT_ADDR, table_offset + i);
|
||||||
|
bw32(bp, B44_FILT_DATA, pattern[i / sizeof(u32)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int b44_magic_pattern(u8 *macaddr, u8 *ppattern, u8 *pmask, int offset)
|
||||||
|
{
|
||||||
|
int magicsync = 6;
|
||||||
|
int k, j, len = offset;
|
||||||
|
int ethaddr_bytes = ETH_ALEN;
|
||||||
|
|
||||||
|
memset(ppattern + offset, 0xff, magicsync);
|
||||||
|
for (j = 0; j < magicsync; j++)
|
||||||
|
set_bit(len++, (unsigned long *) pmask);
|
||||||
|
|
||||||
|
for (j = 0; j < B44_MAX_PATTERNS; j++) {
|
||||||
|
if ((B44_PATTERN_SIZE - len) >= ETH_ALEN)
|
||||||
|
ethaddr_bytes = ETH_ALEN;
|
||||||
|
else
|
||||||
|
ethaddr_bytes = B44_PATTERN_SIZE - len;
|
||||||
|
if (ethaddr_bytes <=0)
|
||||||
|
break;
|
||||||
|
for (k = 0; k< ethaddr_bytes; k++) {
|
||||||
|
ppattern[offset + magicsync +
|
||||||
|
(j * ETH_ALEN) + k] = macaddr[k];
|
||||||
|
len++;
|
||||||
|
set_bit(len, (unsigned long *) pmask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return len - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Setup magic packet patterns in the b44 WOL
|
||||||
|
* pattern matching filter.
|
||||||
|
*/
|
||||||
|
static void b44_setup_pseudo_magicp(struct b44 *bp)
|
||||||
|
{
|
||||||
|
|
||||||
|
u32 val;
|
||||||
|
int plen0, plen1, plen2;
|
||||||
|
u8 *pwol_pattern;
|
||||||
|
u8 pwol_mask[B44_PMASK_SIZE];
|
||||||
|
|
||||||
|
pwol_pattern = kmalloc(B44_PATTERN_SIZE, GFP_KERNEL);
|
||||||
|
if (!pwol_pattern) {
|
||||||
|
printk(KERN_ERR PFX "Memory not available for WOL\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ipv4 magic packet pattern - pattern 0.*/
|
||||||
|
memset(pwol_pattern, 0, B44_PATTERN_SIZE);
|
||||||
|
memset(pwol_mask, 0, B44_PMASK_SIZE);
|
||||||
|
plen0 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
|
||||||
|
B44_ETHIPV4UDP_HLEN);
|
||||||
|
|
||||||
|
bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE, B44_PATTERN_BASE);
|
||||||
|
bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE, B44_PMASK_BASE);
|
||||||
|
|
||||||
|
/* Raw ethernet II magic packet pattern - pattern 1 */
|
||||||
|
memset(pwol_pattern, 0, B44_PATTERN_SIZE);
|
||||||
|
memset(pwol_mask, 0, B44_PMASK_SIZE);
|
||||||
|
plen1 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
|
||||||
|
ETH_HLEN);
|
||||||
|
|
||||||
|
bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE,
|
||||||
|
B44_PATTERN_BASE + B44_PATTERN_SIZE);
|
||||||
|
bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE,
|
||||||
|
B44_PMASK_BASE + B44_PMASK_SIZE);
|
||||||
|
|
||||||
|
/* Ipv6 magic packet pattern - pattern 2 */
|
||||||
|
memset(pwol_pattern, 0, B44_PATTERN_SIZE);
|
||||||
|
memset(pwol_mask, 0, B44_PMASK_SIZE);
|
||||||
|
plen2 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
|
||||||
|
B44_ETHIPV6UDP_HLEN);
|
||||||
|
|
||||||
|
bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE,
|
||||||
|
B44_PATTERN_BASE + B44_PATTERN_SIZE + B44_PATTERN_SIZE);
|
||||||
|
bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE,
|
||||||
|
B44_PMASK_BASE + B44_PMASK_SIZE + B44_PMASK_SIZE);
|
||||||
|
|
||||||
|
kfree(pwol_pattern);
|
||||||
|
|
||||||
|
/* set these pattern's lengths: one less than each real length */
|
||||||
|
val = plen0 | (plen1 << 8) | (plen2 << 16) | WKUP_LEN_ENABLE_THREE;
|
||||||
|
bw32(bp, B44_WKUP_LEN, val);
|
||||||
|
|
||||||
|
/* enable wakeup pattern matching */
|
||||||
|
val = br32(bp, B44_DEVCTRL);
|
||||||
|
bw32(bp, B44_DEVCTRL, val | DEVCTRL_PFE);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static void b44_setup_wol(struct b44 *bp)
|
static void b44_setup_wol(struct b44 *bp)
|
||||||
{
|
{
|
||||||
|
@ -1482,7 +1588,9 @@ static void b44_setup_wol(struct b44 *bp)
|
||||||
val = br32(bp, B44_DEVCTRL);
|
val = br32(bp, B44_DEVCTRL);
|
||||||
bw32(bp, B44_DEVCTRL, val | DEVCTRL_MPM | DEVCTRL_PFE);
|
bw32(bp, B44_DEVCTRL, val | DEVCTRL_MPM | DEVCTRL_PFE);
|
||||||
|
|
||||||
}
|
} else {
|
||||||
|
b44_setup_pseudo_magicp(bp);
|
||||||
|
}
|
||||||
|
|
||||||
val = br32(bp, B44_SBTMSLOW);
|
val = br32(bp, B44_SBTMSLOW);
|
||||||
bw32(bp, B44_SBTMSLOW, val | SBTMSLOW_PE);
|
bw32(bp, B44_SBTMSLOW, val | SBTMSLOW_PE);
|
||||||
|
|
|
@ -24,6 +24,9 @@
|
||||||
#define WKUP_LEN_P3_MASK 0x7f000000 /* Pattern 3 */
|
#define WKUP_LEN_P3_MASK 0x7f000000 /* Pattern 3 */
|
||||||
#define WKUP_LEN_P3_SHIFT 24
|
#define WKUP_LEN_P3_SHIFT 24
|
||||||
#define WKUP_LEN_D3 0x80000000
|
#define WKUP_LEN_D3 0x80000000
|
||||||
|
#define WKUP_LEN_DISABLE 0x80808080
|
||||||
|
#define WKUP_LEN_ENABLE_TWO 0x80800000
|
||||||
|
#define WKUP_LEN_ENABLE_THREE 0x80000000
|
||||||
#define B44_ISTAT 0x0020UL /* Interrupt Status */
|
#define B44_ISTAT 0x0020UL /* Interrupt Status */
|
||||||
#define ISTAT_LS 0x00000020 /* Link Change (B0 only) */
|
#define ISTAT_LS 0x00000020 /* Link Change (B0 only) */
|
||||||
#define ISTAT_PME 0x00000040 /* Power Management Event */
|
#define ISTAT_PME 0x00000040 /* Power Management Event */
|
||||||
|
|
Loading…
Reference in a new issue