diff options
Diffstat (limited to 'drivers/net/b44.c')
-rw-r--r-- | drivers/net/b44.c | 110 |
1 files changed, 109 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 | |||
78 | static char version[] __devinitdata = | 87 | static 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 | ||
1469 | static 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 | |||
1480 | static 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 | */ | ||
1510 | static 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 | ||
1461 | static void b44_setup_wol(struct b44 *bp) | 1567 | static 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); |