aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGary Zambrano <zambrano@broadcom.com>2006-06-20 18:34:36 -0400
committerJeff Garzik <jeff@garzik.org>2006-06-22 23:16:13 -0400
commit725ad800b73a71fe91bfd8859f928852de688ea0 (patch)
tree1612e231baf1bd861c7a5724949a0b7b91966314
parent00e8b3aa1cfd7577fd4019a24f7c3980506f83f3 (diff)
[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>
-rw-r--r--drivers/net/b44.c110
-rw-r--r--drivers/net/b44.h3
2 files changed, 112 insertions, 1 deletions
diff --git a/drivers/net/b44.c b/drivers/net/b44.c
index 12fc67a740ea..98c06752f7ee 100644
--- a/drivers/net/b44.c
+++ b/drivers/net/b44.c
@@ -75,6 +75,15 @@
75/* minimum number of free TX descriptors required to wake up TX process */ 75/* minimum number of free TX descriptors required to wake up TX process */
76#define B44_TX_WAKEUP_THRESH (B44_TX_RING_SIZE / 4) 76#define B44_TX_WAKEUP_THRESH (B44_TX_RING_SIZE / 4)
77 77
78/* b44 internal pattern match filter info */
79#define B44_PATTERN_BASE 0x400
80#define B44_PATTERN_SIZE 0x80
81#define B44_PMASK_BASE 0x600
82#define B44_PMASK_SIZE 0x10
83#define B44_MAX_PATTERNS 16
84#define B44_ETHIPV6UDP_HLEN 62
85#define B44_ETHIPV4UDP_HLEN 42
86
78static char version[] __devinitdata = 87static char version[] __devinitdata =
79 DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; 88 DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
80 89
@@ -1457,6 +1466,103 @@ static void b44_poll_controller(struct net_device *dev)
1457} 1466}
1458#endif 1467#endif
1459 1468
1469static void bwfilter_table(struct b44 *bp, u8 *pp, u32 bytes, u32 table_offset)
1470{
1471 u32 i;
1472 u32 *pattern = (u32 *) pp;
1473
1474 for (i = 0; i < bytes; i += sizeof(u32)) {
1475 bw32(bp, B44_FILT_ADDR, table_offset + i);
1476 bw32(bp, B44_FILT_DATA, pattern[i / sizeof(u32)]);
1477 }
1478}
1479
1480static int b44_magic_pattern(u8 *macaddr, u8 *ppattern, u8 *pmask, int offset)
1481{
1482 int magicsync = 6;
1483 int k, j, len = offset;
1484 int ethaddr_bytes = ETH_ALEN;
1485
1486 memset(ppattern + offset, 0xff, magicsync);
1487 for (j = 0; j < magicsync; j++)
1488 set_bit(len++, (unsigned long *) pmask);
1489
1490 for (j = 0; j < B44_MAX_PATTERNS; j++) {
1491 if ((B44_PATTERN_SIZE - len) >= ETH_ALEN)
1492 ethaddr_bytes = ETH_ALEN;
1493 else
1494 ethaddr_bytes = B44_PATTERN_SIZE - len;
1495 if (ethaddr_bytes <=0)
1496 break;
1497 for (k = 0; k< ethaddr_bytes; k++) {
1498 ppattern[offset + magicsync +
1499 (j * ETH_ALEN) + k] = macaddr[k];
1500 len++;
1501 set_bit(len, (unsigned long *) pmask);
1502 }
1503 }
1504 return len - 1;
1505}
1506
1507/* Setup magic packet patterns in the b44 WOL
1508 * pattern matching filter.
1509 */
1510static void b44_setup_pseudo_magicp(struct b44 *bp)
1511{
1512
1513 u32 val;
1514 int plen0, plen1, plen2;
1515 u8 *pwol_pattern;
1516 u8 pwol_mask[B44_PMASK_SIZE];
1517
1518 pwol_pattern = kmalloc(B44_PATTERN_SIZE, GFP_KERNEL);
1519 if (!pwol_pattern) {
1520 printk(KERN_ERR PFX "Memory not available for WOL\n");
1521 return;
1522 }
1523
1524 /* Ipv4 magic packet pattern - pattern 0.*/
1525 memset(pwol_pattern, 0, B44_PATTERN_SIZE);
1526 memset(pwol_mask, 0, B44_PMASK_SIZE);
1527 plen0 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
1528 B44_ETHIPV4UDP_HLEN);
1529
1530 bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE, B44_PATTERN_BASE);
1531 bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE, B44_PMASK_BASE);
1532
1533 /* Raw ethernet II magic packet pattern - pattern 1 */
1534 memset(pwol_pattern, 0, B44_PATTERN_SIZE);
1535 memset(pwol_mask, 0, B44_PMASK_SIZE);
1536 plen1 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
1537 ETH_HLEN);
1538
1539 bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE,
1540 B44_PATTERN_BASE + B44_PATTERN_SIZE);
1541 bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE,
1542 B44_PMASK_BASE + B44_PMASK_SIZE);
1543
1544 /* Ipv6 magic packet pattern - pattern 2 */
1545 memset(pwol_pattern, 0, B44_PATTERN_SIZE);
1546 memset(pwol_mask, 0, B44_PMASK_SIZE);
1547 plen2 = b44_magic_pattern(bp->dev->dev_addr, pwol_pattern, pwol_mask,
1548 B44_ETHIPV6UDP_HLEN);
1549
1550 bwfilter_table(bp, pwol_pattern, B44_PATTERN_SIZE,
1551 B44_PATTERN_BASE + B44_PATTERN_SIZE + B44_PATTERN_SIZE);
1552 bwfilter_table(bp, pwol_mask, B44_PMASK_SIZE,
1553 B44_PMASK_BASE + B44_PMASK_SIZE + B44_PMASK_SIZE);
1554
1555 kfree(pwol_pattern);
1556
1557 /* set these pattern's lengths: one less than each real length */
1558 val = plen0 | (plen1 << 8) | (plen2 << 16) | WKUP_LEN_ENABLE_THREE;
1559 bw32(bp, B44_WKUP_LEN, val);
1560
1561 /* enable wakeup pattern matching */
1562 val = br32(bp, B44_DEVCTRL);
1563 bw32(bp, B44_DEVCTRL, val | DEVCTRL_PFE);
1564
1565}
1460 1566
1461static void b44_setup_wol(struct b44 *bp) 1567static void b44_setup_wol(struct b44 *bp)
1462{ 1568{
@@ -1482,7 +1588,9 @@ static void b44_setup_wol(struct b44 *bp)
1482 val = br32(bp, B44_DEVCTRL); 1588 val = br32(bp, B44_DEVCTRL);
1483 bw32(bp, B44_DEVCTRL, val | DEVCTRL_MPM | DEVCTRL_PFE); 1589 bw32(bp, B44_DEVCTRL, val | DEVCTRL_MPM | DEVCTRL_PFE);
1484 1590
1485 } 1591 } else {
1592 b44_setup_pseudo_magicp(bp);
1593 }
1486 1594
1487 val = br32(bp, B44_SBTMSLOW); 1595 val = br32(bp, B44_SBTMSLOW);
1488 bw32(bp, B44_SBTMSLOW, val | SBTMSLOW_PE); 1596 bw32(bp, B44_SBTMSLOW, val | SBTMSLOW_PE);
diff --git a/drivers/net/b44.h b/drivers/net/b44.h
index 1f47777b848b..4944507fad23 100644
--- a/drivers/net/b44.h
+++ b/drivers/net/b44.h
@@ -24,6 +24,9 @@
24#define WKUP_LEN_P3_MASK 0x7f000000 /* Pattern 3 */ 24#define WKUP_LEN_P3_MASK 0x7f000000 /* Pattern 3 */
25#define WKUP_LEN_P3_SHIFT 24 25#define WKUP_LEN_P3_SHIFT 24
26#define WKUP_LEN_D3 0x80000000 26#define WKUP_LEN_D3 0x80000000
27#define WKUP_LEN_DISABLE 0x80808080
28#define WKUP_LEN_ENABLE_TWO 0x80800000
29#define WKUP_LEN_ENABLE_THREE 0x80000000
27#define B44_ISTAT 0x0020UL /* Interrupt Status */ 30#define B44_ISTAT 0x0020UL /* Interrupt Status */
28#define ISTAT_LS 0x00000020 /* Link Change (B0 only) */ 31#define ISTAT_LS 0x00000020 /* Link Change (B0 only) */
29#define ISTAT_PME 0x00000040 /* Power Management Event */ 32#define ISTAT_PME 0x00000040 /* Power Management Event */