diff options
| author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-04-29 13:48:48 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-04-29 13:48:48 -0400 |
| commit | e389f9aec689209724105ae80a6c91fd2e747bc9 (patch) | |
| tree | 3cc88a3e785e4f2ffeaa9dad0da695cfa437d4fe /drivers/net/ucc_geth.c | |
| parent | f73b0a08eae0e28c50db5dd5ab8245546918bfb6 (diff) | |
| parent | b4cf205846463a0a23a917bb18ad833bc9a8c0bb (diff) | |
Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6
* 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6: (107 commits)
smc911x: fix compilation breakage wjen debug is on
[netdrvr] eexpress: minor corrections
add NAPI support to sb1250-mac.c
ixgb: ROUND_UP macro cleanup in drivers/net/ixgb
e1000: ROUND_UP macro cleanup in drivers/net/e1000
Generic HDLC sparse annotations
e100: Optionally use I/O mode only to access register space
e100: allow bad MAC address when running with invalid eeprom csum
ehea: fix for dlpar support
ehea: fix for sysfs entries
3C509: Remove unnecessary include of <linux/pm_legacy.h>
NetXen: Fix for vmalloc issues
NetXen: Fixes for Power PC architecture
NetXen: Port swap feature for multi port cards
NetXen: Removal of redundant macros
NetXen: Multi PCI support for Quad cards
NetXen: Removal of redundant argument passing
NetXen: Use multiple PCI functions
[netdrvr e100] experiment with doing RX in a similar manner to eepro100
[PATCH] ieee80211: add missing global needed by IEEE80211_DEBUG_XXXX
...
Diffstat (limited to 'drivers/net/ucc_geth.c')
| -rw-r--r-- | drivers/net/ucc_geth.c | 946 |
1 files changed, 346 insertions, 600 deletions
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index 639e1e6913bf..16b9acdabbe8 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include <linux/fsl_devices.h> | 29 | #include <linux/fsl_devices.h> |
| 30 | #include <linux/ethtool.h> | 30 | #include <linux/ethtool.h> |
| 31 | #include <linux/mii.h> | 31 | #include <linux/mii.h> |
| 32 | #include <linux/phy.h> | ||
| 32 | #include <linux/workqueue.h> | 33 | #include <linux/workqueue.h> |
| 33 | 34 | ||
| 34 | #include <asm/of_platform.h> | 35 | #include <asm/of_platform.h> |
| @@ -41,12 +42,13 @@ | |||
| 41 | #include <asm/ucc_fast.h> | 42 | #include <asm/ucc_fast.h> |
| 42 | 43 | ||
| 43 | #include "ucc_geth.h" | 44 | #include "ucc_geth.h" |
| 44 | #include "ucc_geth_phy.h" | 45 | #include "ucc_geth_mii.h" |
| 45 | 46 | ||
| 46 | #undef DEBUG | 47 | #undef DEBUG |
| 47 | 48 | ||
| 48 | #define DRV_DESC "QE UCC Gigabit Ethernet Controller version:Sept 11, 2006" | 49 | #define DRV_DESC "QE UCC Gigabit Ethernet Controller" |
| 49 | #define DRV_NAME "ucc_geth" | 50 | #define DRV_NAME "ucc_geth" |
| 51 | #define DRV_VERSION "1.1" | ||
| 50 | 52 | ||
| 51 | #define ugeth_printk(level, format, arg...) \ | 53 | #define ugeth_printk(level, format, arg...) \ |
| 52 | printk(level format "\n", ## arg) | 54 | printk(level format "\n", ## arg) |
| @@ -73,22 +75,13 @@ static struct ucc_geth_info ugeth_primary_info = { | |||
| 73 | .bd_mem_part = MEM_PART_SYSTEM, | 75 | .bd_mem_part = MEM_PART_SYSTEM, |
| 74 | .rtsm = UCC_FAST_SEND_IDLES_BETWEEN_FRAMES, | 76 | .rtsm = UCC_FAST_SEND_IDLES_BETWEEN_FRAMES, |
| 75 | .max_rx_buf_length = 1536, | 77 | .max_rx_buf_length = 1536, |
| 76 | /* FIXME: should be changed in run time for 1G and 100M */ | 78 | /* adjusted at startup if max-speed 1000 */ |
| 77 | #ifdef CONFIG_UGETH_HAS_GIGA | ||
| 78 | .urfs = UCC_GETH_URFS_GIGA_INIT, | ||
| 79 | .urfet = UCC_GETH_URFET_GIGA_INIT, | ||
| 80 | .urfset = UCC_GETH_URFSET_GIGA_INIT, | ||
| 81 | .utfs = UCC_GETH_UTFS_GIGA_INIT, | ||
| 82 | .utfet = UCC_GETH_UTFET_GIGA_INIT, | ||
| 83 | .utftt = UCC_GETH_UTFTT_GIGA_INIT, | ||
| 84 | #else | ||
| 85 | .urfs = UCC_GETH_URFS_INIT, | 79 | .urfs = UCC_GETH_URFS_INIT, |
| 86 | .urfet = UCC_GETH_URFET_INIT, | 80 | .urfet = UCC_GETH_URFET_INIT, |
| 87 | .urfset = UCC_GETH_URFSET_INIT, | 81 | .urfset = UCC_GETH_URFSET_INIT, |
| 88 | .utfs = UCC_GETH_UTFS_INIT, | 82 | .utfs = UCC_GETH_UTFS_INIT, |
| 89 | .utfet = UCC_GETH_UTFET_INIT, | 83 | .utfet = UCC_GETH_UTFET_INIT, |
| 90 | .utftt = UCC_GETH_UTFTT_INIT, | 84 | .utftt = UCC_GETH_UTFTT_INIT, |
| 91 | #endif | ||
| 92 | .ufpt = 256, | 85 | .ufpt = 256, |
| 93 | .mode = UCC_FAST_PROTOCOL_MODE_ETHERNET, | 86 | .mode = UCC_FAST_PROTOCOL_MODE_ETHERNET, |
| 94 | .ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL, | 87 | .ttx_trx = UCC_FAST_GUMR_TRANSPARENT_TTX_TRX_NORMAL, |
| @@ -217,70 +210,6 @@ static struct list_head *dequeue(struct list_head *lh) | |||
| 217 | } | 210 | } |
| 218 | } | 211 | } |
| 219 | 212 | ||
| 220 | static int get_interface_details(enum enet_interface enet_interface, | ||
| 221 | enum enet_speed *speed, | ||
| 222 | int *r10m, | ||
| 223 | int *rmm, | ||
| 224 | int *rpm, | ||
| 225 | int *tbi, int *limited_to_full_duplex) | ||
| 226 | { | ||
| 227 | /* Analyze enet_interface according to Interface Mode | ||
| 228 | Configuration table */ | ||
| 229 | switch (enet_interface) { | ||
| 230 | case ENET_10_MII: | ||
| 231 | *speed = ENET_SPEED_10BT; | ||
| 232 | break; | ||
| 233 | case ENET_10_RMII: | ||
| 234 | *speed = ENET_SPEED_10BT; | ||
| 235 | *r10m = 1; | ||
| 236 | *rmm = 1; | ||
| 237 | break; | ||
| 238 | case ENET_10_RGMII: | ||
| 239 | *speed = ENET_SPEED_10BT; | ||
| 240 | *rpm = 1; | ||
| 241 | *r10m = 1; | ||
| 242 | *limited_to_full_duplex = 1; | ||
| 243 | break; | ||
| 244 | case ENET_100_MII: | ||
| 245 | *speed = ENET_SPEED_100BT; | ||
| 246 | break; | ||
| 247 | case ENET_100_RMII: | ||
| 248 | *speed = ENET_SPEED_100BT; | ||
| 249 | *rmm = 1; | ||
| 250 | break; | ||
| 251 | case ENET_100_RGMII: | ||
| 252 | *speed = ENET_SPEED_100BT; | ||
| 253 | *rpm = 1; | ||
| 254 | *limited_to_full_duplex = 1; | ||
| 255 | break; | ||
| 256 | case ENET_1000_GMII: | ||
| 257 | *speed = ENET_SPEED_1000BT; | ||
| 258 | *limited_to_full_duplex = 1; | ||
| 259 | break; | ||
| 260 | case ENET_1000_RGMII: | ||
| 261 | *speed = ENET_SPEED_1000BT; | ||
| 262 | *rpm = 1; | ||
| 263 | *limited_to_full_duplex = 1; | ||
| 264 | break; | ||
| 265 | case ENET_1000_TBI: | ||
| 266 | *speed = ENET_SPEED_1000BT; | ||
| 267 | *tbi = 1; | ||
| 268 | *limited_to_full_duplex = 1; | ||
| 269 | break; | ||
| 270 | case ENET_1000_RTBI: | ||
| 271 | *speed = ENET_SPEED_1000BT; | ||
| 272 | *rpm = 1; | ||
| 273 | *tbi = 1; | ||
| 274 | *limited_to_full_duplex = 1; | ||
| 275 | break; | ||
| 276 | default: | ||
| 277 | return -EINVAL; | ||
| 278 | break; | ||
| 279 | } | ||
| 280 | |||
| 281 | return 0; | ||
| 282 | } | ||
| 283 | |||
| 284 | static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, u8 *bd) | 213 | static struct sk_buff *get_new_skb(struct ucc_geth_private *ugeth, u8 *bd) |
| 285 | { | 214 | { |
| 286 | struct sk_buff *skb = NULL; | 215 | struct sk_buff *skb = NULL; |
| @@ -758,24 +687,6 @@ static void dump_regs(struct ucc_geth_private *ugeth) | |||
| 758 | ugeth_info("hafdup : addr - 0x%08x, val - 0x%08x", | 687 | ugeth_info("hafdup : addr - 0x%08x, val - 0x%08x", |
| 759 | (u32) & ugeth->ug_regs->hafdup, | 688 | (u32) & ugeth->ug_regs->hafdup, |
| 760 | in_be32(&ugeth->ug_regs->hafdup)); | 689 | in_be32(&ugeth->ug_regs->hafdup)); |
| 761 | ugeth_info("miimcfg : addr - 0x%08x, val - 0x%08x", | ||
| 762 | (u32) & ugeth->ug_regs->miimng.miimcfg, | ||
| 763 | in_be32(&ugeth->ug_regs->miimng.miimcfg)); | ||
| 764 | ugeth_info("miimcom : addr - 0x%08x, val - 0x%08x", | ||
| 765 | (u32) & ugeth->ug_regs->miimng.miimcom, | ||
| 766 | in_be32(&ugeth->ug_regs->miimng.miimcom)); | ||
| 767 | ugeth_info("miimadd : addr - 0x%08x, val - 0x%08x", | ||
| 768 | (u32) & ugeth->ug_regs->miimng.miimadd, | ||
| 769 | in_be32(&ugeth->ug_regs->miimng.miimadd)); | ||
| 770 | ugeth_info("miimcon : addr - 0x%08x, val - 0x%08x", | ||
| 771 | (u32) & ugeth->ug_regs->miimng.miimcon, | ||
| 772 | in_be32(&ugeth->ug_regs->miimng.miimcon)); | ||
| 773 | ugeth_info("miimstat : addr - 0x%08x, val - 0x%08x", | ||
| 774 | (u32) & ugeth->ug_regs->miimng.miimstat, | ||
| 775 | in_be32(&ugeth->ug_regs->miimng.miimstat)); | ||
| 776 | ugeth_info("miimmind : addr - 0x%08x, val - 0x%08x", | ||
| 777 | (u32) & ugeth->ug_regs->miimng.miimind, | ||
| 778 | in_be32(&ugeth->ug_regs->miimng.miimind)); | ||
| 779 | ugeth_info("ifctl : addr - 0x%08x, val - 0x%08x", | 690 | ugeth_info("ifctl : addr - 0x%08x, val - 0x%08x", |
| 780 | (u32) & ugeth->ug_regs->ifctl, | 691 | (u32) & ugeth->ug_regs->ifctl, |
| 781 | in_be32(&ugeth->ug_regs->ifctl)); | 692 | in_be32(&ugeth->ug_regs->ifctl)); |
| @@ -1425,27 +1336,6 @@ static int init_mac_station_addr_regs(u8 address_byte_0, | |||
| 1425 | return 0; | 1336 | return 0; |
| 1426 | } | 1337 | } |
| 1427 | 1338 | ||
| 1428 | static int init_mac_duplex_mode(int full_duplex, | ||
| 1429 | int limited_to_full_duplex, | ||
| 1430 | volatile u32 *maccfg2_register) | ||
| 1431 | { | ||
| 1432 | u32 value = 0; | ||
| 1433 | |||
| 1434 | /* some interfaces must work in full duplex mode */ | ||
| 1435 | if ((full_duplex == 0) && (limited_to_full_duplex == 1)) | ||
| 1436 | return -EINVAL; | ||
| 1437 | |||
| 1438 | value = in_be32(maccfg2_register); | ||
| 1439 | |||
| 1440 | if (full_duplex) | ||
| 1441 | value |= MACCFG2_FDX; | ||
| 1442 | else | ||
| 1443 | value &= ~MACCFG2_FDX; | ||
| 1444 | |||
| 1445 | out_be32(maccfg2_register, value); | ||
| 1446 | return 0; | ||
| 1447 | } | ||
| 1448 | |||
| 1449 | static int init_check_frame_length_mode(int length_check, | 1339 | static int init_check_frame_length_mode(int length_check, |
| 1450 | volatile u32 *maccfg2_register) | 1340 | volatile u32 *maccfg2_register) |
| 1451 | { | 1341 | { |
| @@ -1477,40 +1367,6 @@ static int init_preamble_length(u8 preamble_length, | |||
| 1477 | return 0; | 1367 | return 0; |
| 1478 | } | 1368 | } |
| 1479 | 1369 | ||
| 1480 | static int init_mii_management_configuration(int reset_mgmt, | ||
| 1481 | int preamble_supress, | ||
| 1482 | volatile u32 *miimcfg_register, | ||
| 1483 | volatile u32 *miimind_register) | ||
| 1484 | { | ||
| 1485 | unsigned int timeout = PHY_INIT_TIMEOUT; | ||
| 1486 | u32 value = 0; | ||
| 1487 | |||
| 1488 | value = in_be32(miimcfg_register); | ||
| 1489 | if (reset_mgmt) { | ||
| 1490 | value |= MIIMCFG_RESET_MANAGEMENT; | ||
| 1491 | out_be32(miimcfg_register, value); | ||
| 1492 | } | ||
| 1493 | |||
| 1494 | value = 0; | ||
| 1495 | |||
| 1496 | if (preamble_supress) | ||
| 1497 | value |= MIIMCFG_NO_PREAMBLE; | ||
| 1498 | |||
| 1499 | value |= UCC_GETH_MIIMCFG_MNGMNT_CLC_DIV_INIT; | ||
| 1500 | out_be32(miimcfg_register, value); | ||
| 1501 | |||
| 1502 | /* Wait until the bus is free */ | ||
| 1503 | while ((in_be32(miimind_register) & MIIMIND_BUSY) && timeout--) | ||
| 1504 | cpu_relax(); | ||
| 1505 | |||
| 1506 | if (timeout <= 0) { | ||
| 1507 | ugeth_err("%s: The MII Bus is stuck!", __FUNCTION__); | ||
| 1508 | return -ETIMEDOUT; | ||
| 1509 | } | ||
| 1510 | |||
| 1511 | return 0; | ||
| 1512 | } | ||
| 1513 | |||
| 1514 | static int init_rx_parameters(int reject_broadcast, | 1370 | static int init_rx_parameters(int reject_broadcast, |
| 1515 | int receive_short_frames, | 1371 | int receive_short_frames, |
| 1516 | int promiscuous, volatile u32 *upsmr_register) | 1372 | int promiscuous, volatile u32 *upsmr_register) |
| @@ -1570,10 +1426,8 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) | |||
| 1570 | struct ucc_geth_info *ug_info; | 1426 | struct ucc_geth_info *ug_info; |
| 1571 | struct ucc_geth *ug_regs; | 1427 | struct ucc_geth *ug_regs; |
| 1572 | struct ucc_fast *uf_regs; | 1428 | struct ucc_fast *uf_regs; |
| 1573 | enum enet_speed speed; | 1429 | int ret_val; |
| 1574 | int ret_val, rpm = 0, tbi = 0, r10m = 0, rmm = | 1430 | u32 upsmr, maccfg2, tbiBaseAddress; |
| 1575 | 0, limited_to_full_duplex = 0; | ||
| 1576 | u32 upsmr, maccfg2, utbipar, tbiBaseAddress; | ||
| 1577 | u16 value; | 1431 | u16 value; |
| 1578 | 1432 | ||
| 1579 | ugeth_vdbg("%s: IN", __FUNCTION__); | 1433 | ugeth_vdbg("%s: IN", __FUNCTION__); |
| @@ -1582,24 +1436,13 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) | |||
| 1582 | ug_regs = ugeth->ug_regs; | 1436 | ug_regs = ugeth->ug_regs; |
| 1583 | uf_regs = ugeth->uccf->uf_regs; | 1437 | uf_regs = ugeth->uccf->uf_regs; |
| 1584 | 1438 | ||
| 1585 | /* Analyze enet_interface according to Interface Mode Configuration | ||
| 1586 | table */ | ||
| 1587 | ret_val = | ||
| 1588 | get_interface_details(ug_info->enet_interface, &speed, &r10m, &rmm, | ||
| 1589 | &rpm, &tbi, &limited_to_full_duplex); | ||
| 1590 | if (ret_val != 0) { | ||
| 1591 | ugeth_err | ||
| 1592 | ("%s: half duplex not supported in requested configuration.", | ||
| 1593 | __FUNCTION__); | ||
| 1594 | return ret_val; | ||
| 1595 | } | ||
| 1596 | |||
| 1597 | /* Set MACCFG2 */ | 1439 | /* Set MACCFG2 */ |
| 1598 | maccfg2 = in_be32(&ug_regs->maccfg2); | 1440 | maccfg2 = in_be32(&ug_regs->maccfg2); |
| 1599 | maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK; | 1441 | maccfg2 &= ~MACCFG2_INTERFACE_MODE_MASK; |
| 1600 | if ((speed == ENET_SPEED_10BT) || (speed == ENET_SPEED_100BT)) | 1442 | if ((ugeth->max_speed == SPEED_10) || |
| 1443 | (ugeth->max_speed == SPEED_100)) | ||
| 1601 | maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; | 1444 | maccfg2 |= MACCFG2_INTERFACE_MODE_NIBBLE; |
| 1602 | else if (speed == ENET_SPEED_1000BT) | 1445 | else if (ugeth->max_speed == SPEED_1000) |
| 1603 | maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; | 1446 | maccfg2 |= MACCFG2_INTERFACE_MODE_BYTE; |
| 1604 | maccfg2 |= ug_info->padAndCrc; | 1447 | maccfg2 |= ug_info->padAndCrc; |
| 1605 | out_be32(&ug_regs->maccfg2, maccfg2); | 1448 | out_be32(&ug_regs->maccfg2, maccfg2); |
| @@ -1607,54 +1450,39 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) | |||
| 1607 | /* Set UPSMR */ | 1450 | /* Set UPSMR */ |
| 1608 | upsmr = in_be32(&uf_regs->upsmr); | 1451 | upsmr = in_be32(&uf_regs->upsmr); |
| 1609 | upsmr &= ~(UPSMR_RPM | UPSMR_R10M | UPSMR_TBIM | UPSMR_RMM); | 1452 | upsmr &= ~(UPSMR_RPM | UPSMR_R10M | UPSMR_TBIM | UPSMR_RMM); |
| 1610 | if (rpm) | 1453 | if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) || |
| 1454 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) || | ||
| 1455 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) || | ||
| 1456 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { | ||
| 1611 | upsmr |= UPSMR_RPM; | 1457 | upsmr |= UPSMR_RPM; |
| 1612 | if (r10m) | 1458 | switch (ugeth->max_speed) { |
| 1613 | upsmr |= UPSMR_R10M; | 1459 | case SPEED_10: |
| 1614 | if (tbi) | 1460 | upsmr |= UPSMR_R10M; |
| 1461 | /* FALLTHROUGH */ | ||
| 1462 | case SPEED_100: | ||
| 1463 | if (ugeth->phy_interface != PHY_INTERFACE_MODE_RTBI) | ||
| 1464 | upsmr |= UPSMR_RMM; | ||
| 1465 | } | ||
| 1466 | } | ||
| 1467 | if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) || | ||
| 1468 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { | ||
| 1615 | upsmr |= UPSMR_TBIM; | 1469 | upsmr |= UPSMR_TBIM; |
| 1616 | if (rmm) | 1470 | } |
| 1617 | upsmr |= UPSMR_RMM; | ||
| 1618 | out_be32(&uf_regs->upsmr, upsmr); | 1471 | out_be32(&uf_regs->upsmr, upsmr); |
| 1619 | 1472 | ||
| 1620 | /* Set UTBIPAR */ | ||
| 1621 | utbipar = in_be32(&ug_regs->utbipar); | ||
| 1622 | utbipar &= ~UTBIPAR_PHY_ADDRESS_MASK; | ||
| 1623 | if (tbi) | ||
| 1624 | utbipar |= | ||
| 1625 | (ug_info->phy_address + | ||
| 1626 | ugeth->ug_info->uf_info. | ||
| 1627 | ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT; | ||
| 1628 | else | ||
| 1629 | utbipar |= | ||
| 1630 | (0x10 + | ||
| 1631 | ugeth->ug_info->uf_info. | ||
| 1632 | ucc_num) << UTBIPAR_PHY_ADDRESS_SHIFT; | ||
| 1633 | out_be32(&ug_regs->utbipar, utbipar); | ||
| 1634 | |||
| 1635 | /* Disable autonegotiation in tbi mode, because by default it | 1473 | /* Disable autonegotiation in tbi mode, because by default it |
| 1636 | comes up in autonegotiation mode. */ | 1474 | comes up in autonegotiation mode. */ |
| 1637 | /* Note that this depends on proper setting in utbipar register. */ | 1475 | /* Note that this depends on proper setting in utbipar register. */ |
| 1638 | if (tbi) { | 1476 | if ((ugeth->phy_interface == PHY_INTERFACE_MODE_TBI) || |
| 1477 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { | ||
| 1639 | tbiBaseAddress = in_be32(&ug_regs->utbipar); | 1478 | tbiBaseAddress = in_be32(&ug_regs->utbipar); |
| 1640 | tbiBaseAddress &= UTBIPAR_PHY_ADDRESS_MASK; | 1479 | tbiBaseAddress &= UTBIPAR_PHY_ADDRESS_MASK; |
| 1641 | tbiBaseAddress >>= UTBIPAR_PHY_ADDRESS_SHIFT; | 1480 | tbiBaseAddress >>= UTBIPAR_PHY_ADDRESS_SHIFT; |
| 1642 | value = | 1481 | value = ugeth->phydev->bus->read(ugeth->phydev->bus, |
| 1643 | ugeth->mii_info->mdio_read(ugeth->dev, (u8) tbiBaseAddress, | 1482 | (u8) tbiBaseAddress, ENET_TBI_MII_CR); |
| 1644 | ENET_TBI_MII_CR); | ||
| 1645 | value &= ~0x1000; /* Turn off autonegotiation */ | 1483 | value &= ~0x1000; /* Turn off autonegotiation */ |
| 1646 | ugeth->mii_info->mdio_write(ugeth->dev, (u8) tbiBaseAddress, | 1484 | ugeth->phydev->bus->write(ugeth->phydev->bus, |
| 1647 | ENET_TBI_MII_CR, value); | 1485 | (u8) tbiBaseAddress, ENET_TBI_MII_CR, value); |
| 1648 | } | ||
| 1649 | |||
| 1650 | ret_val = init_mac_duplex_mode(1, | ||
| 1651 | limited_to_full_duplex, | ||
| 1652 | &ug_regs->maccfg2); | ||
| 1653 | if (ret_val != 0) { | ||
| 1654 | ugeth_err | ||
| 1655 | ("%s: half duplex not supported in requested configuration.", | ||
| 1656 | __FUNCTION__); | ||
| 1657 | return ret_val; | ||
| 1658 | } | 1486 | } |
| 1659 | 1487 | ||
| 1660 | init_check_frame_length_mode(ug_info->lengthCheckRx, &ug_regs->maccfg2); | 1488 | init_check_frame_length_mode(ug_info->lengthCheckRx, &ug_regs->maccfg2); |
| @@ -1676,76 +1504,88 @@ static int adjust_enet_interface(struct ucc_geth_private *ugeth) | |||
| 1676 | * function converts those variables into the appropriate | 1504 | * function converts those variables into the appropriate |
| 1677 | * register values, and can bring down the device if needed. | 1505 | * register values, and can bring down the device if needed. |
| 1678 | */ | 1506 | */ |
| 1507 | |||
| 1679 | static void adjust_link(struct net_device *dev) | 1508 | static void adjust_link(struct net_device *dev) |
| 1680 | { | 1509 | { |
| 1681 | struct ucc_geth_private *ugeth = netdev_priv(dev); | 1510 | struct ucc_geth_private *ugeth = netdev_priv(dev); |
| 1682 | struct ucc_geth *ug_regs; | 1511 | struct ucc_geth *ug_regs; |
| 1683 | u32 tempval; | 1512 | struct ucc_fast *uf_regs; |
| 1684 | struct ugeth_mii_info *mii_info = ugeth->mii_info; | 1513 | struct phy_device *phydev = ugeth->phydev; |
| 1514 | unsigned long flags; | ||
| 1515 | int new_state = 0; | ||
| 1685 | 1516 | ||
| 1686 | ug_regs = ugeth->ug_regs; | 1517 | ug_regs = ugeth->ug_regs; |
| 1518 | uf_regs = ugeth->uccf->uf_regs; | ||
| 1687 | 1519 | ||
| 1688 | if (mii_info->link) { | 1520 | spin_lock_irqsave(&ugeth->lock, flags); |
| 1521 | |||
| 1522 | if (phydev->link) { | ||
| 1523 | u32 tempval = in_be32(&ug_regs->maccfg2); | ||
| 1524 | u32 upsmr = in_be32(&uf_regs->upsmr); | ||
| 1689 | /* Now we make sure that we can be in full duplex mode. | 1525 | /* Now we make sure that we can be in full duplex mode. |
| 1690 | * If not, we operate in half-duplex mode. */ | 1526 | * If not, we operate in half-duplex mode. */ |
| 1691 | if (mii_info->duplex != ugeth->oldduplex) { | 1527 | if (phydev->duplex != ugeth->oldduplex) { |
| 1692 | if (!(mii_info->duplex)) { | 1528 | new_state = 1; |
| 1693 | tempval = in_be32(&ug_regs->maccfg2); | 1529 | if (!(phydev->duplex)) |
| 1694 | tempval &= ~(MACCFG2_FDX); | 1530 | tempval &= ~(MACCFG2_FDX); |
| 1695 | out_be32(&ug_regs->maccfg2, tempval); | 1531 | else |
| 1696 | |||
| 1697 | ugeth_info("%s: Half Duplex", dev->name); | ||
| 1698 | } else { | ||
| 1699 | tempval = in_be32(&ug_regs->maccfg2); | ||
| 1700 | tempval |= MACCFG2_FDX; | 1532 | tempval |= MACCFG2_FDX; |
| 1701 | out_be32(&ug_regs->maccfg2, tempval); | 1533 | ugeth->oldduplex = phydev->duplex; |
| 1702 | |||
| 1703 | ugeth_info("%s: Full Duplex", dev->name); | ||
| 1704 | } | ||
| 1705 | |||
| 1706 | ugeth->oldduplex = mii_info->duplex; | ||
| 1707 | } | 1534 | } |
| 1708 | 1535 | ||
| 1709 | if (mii_info->speed != ugeth->oldspeed) { | 1536 | if (phydev->speed != ugeth->oldspeed) { |
| 1710 | switch (mii_info->speed) { | 1537 | new_state = 1; |
| 1711 | case 1000: | 1538 | switch (phydev->speed) { |
| 1712 | ugeth->ug_info->enet_interface = ENET_1000_RGMII; | 1539 | case SPEED_1000: |
| 1540 | tempval = ((tempval & | ||
| 1541 | ~(MACCFG2_INTERFACE_MODE_MASK)) | | ||
| 1542 | MACCFG2_INTERFACE_MODE_BYTE); | ||
| 1713 | break; | 1543 | break; |
| 1714 | case 100: | 1544 | case SPEED_100: |
| 1715 | ugeth->ug_info->enet_interface = ENET_100_RGMII; | 1545 | case SPEED_10: |
| 1716 | break; | 1546 | tempval = ((tempval & |
| 1717 | case 10: | 1547 | ~(MACCFG2_INTERFACE_MODE_MASK)) | |
| 1718 | ugeth->ug_info->enet_interface = ENET_10_RGMII; | 1548 | MACCFG2_INTERFACE_MODE_NIBBLE); |
| 1549 | /* if reduced mode, re-set UPSMR.R10M */ | ||
| 1550 | if ((ugeth->phy_interface == PHY_INTERFACE_MODE_RMII) || | ||
| 1551 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII) || | ||
| 1552 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RGMII_ID) || | ||
| 1553 | (ugeth->phy_interface == PHY_INTERFACE_MODE_RTBI)) { | ||
| 1554 | if (phydev->speed == SPEED_10) | ||
| 1555 | upsmr |= UPSMR_R10M; | ||
| 1556 | else | ||
| 1557 | upsmr &= ~(UPSMR_R10M); | ||
| 1558 | } | ||
| 1719 | break; | 1559 | break; |
| 1720 | default: | 1560 | default: |
| 1721 | ugeth_warn | 1561 | if (netif_msg_link(ugeth)) |
| 1722 | ("%s: Ack! Speed (%d) is not 10/100/1000!", | 1562 | ugeth_warn( |
| 1723 | dev->name, mii_info->speed); | 1563 | "%s: Ack! Speed (%d) is not 10/100/1000!", |
| 1564 | dev->name, phydev->speed); | ||
| 1724 | break; | 1565 | break; |
| 1725 | } | 1566 | } |
| 1726 | adjust_enet_interface(ugeth); | 1567 | ugeth->oldspeed = phydev->speed; |
| 1727 | |||
| 1728 | ugeth_info("%s: Speed %dBT", dev->name, | ||
| 1729 | mii_info->speed); | ||
| 1730 | |||
| 1731 | ugeth->oldspeed = mii_info->speed; | ||
| 1732 | } | 1568 | } |
| 1733 | 1569 | ||
| 1570 | out_be32(&ug_regs->maccfg2, tempval); | ||
| 1571 | out_be32(&uf_regs->upsmr, upsmr); | ||
| 1572 | |||
| 1734 | if (!ugeth->oldlink) { | 1573 | if (!ugeth->oldlink) { |
| 1735 | ugeth_info("%s: Link is up", dev->name); | 1574 | new_state = 1; |
| 1736 | ugeth->oldlink = 1; | 1575 | ugeth->oldlink = 1; |
| 1737 | netif_carrier_on(dev); | ||
| 1738 | netif_schedule(dev); | 1576 | netif_schedule(dev); |
| 1739 | } | 1577 | } |
| 1740 | } else { | 1578 | } else if (ugeth->oldlink) { |
| 1741 | if (ugeth->oldlink) { | 1579 | new_state = 1; |
| 1742 | ugeth_info("%s: Link is down", dev->name); | ||
| 1743 | ugeth->oldlink = 0; | 1580 | ugeth->oldlink = 0; |
| 1744 | ugeth->oldspeed = 0; | 1581 | ugeth->oldspeed = 0; |
| 1745 | ugeth->oldduplex = -1; | 1582 | ugeth->oldduplex = -1; |
| 1746 | netif_carrier_off(dev); | ||
| 1747 | } | ||
| 1748 | } | 1583 | } |
| 1584 | |||
| 1585 | if (new_state && netif_msg_link(ugeth)) | ||
| 1586 | phy_print_status(phydev); | ||
| 1587 | |||
| 1588 | spin_unlock_irqrestore(&ugeth->lock, flags); | ||
| 1749 | } | 1589 | } |
| 1750 | 1590 | ||
| 1751 | /* Configure the PHY for dev. | 1591 | /* Configure the PHY for dev. |
| @@ -1753,102 +1593,40 @@ static void adjust_link(struct net_device *dev) | |||
| 1753 | */ | 1593 | */ |
| 1754 | static int init_phy(struct net_device *dev) | 1594 | static int init_phy(struct net_device *dev) |
| 1755 | { | 1595 | { |
| 1756 | struct ucc_geth_private *ugeth = netdev_priv(dev); | 1596 | struct ucc_geth_private *priv = netdev_priv(dev); |
| 1757 | struct phy_info *curphy; | 1597 | struct phy_device *phydev; |
| 1758 | struct ucc_mii_mng *mii_regs; | 1598 | char phy_id[BUS_ID_SIZE]; |
| 1759 | struct ugeth_mii_info *mii_info; | ||
| 1760 | int err; | ||
| 1761 | 1599 | ||
| 1762 | mii_regs = &ugeth->ug_regs->miimng; | 1600 | priv->oldlink = 0; |
| 1601 | priv->oldspeed = 0; | ||
| 1602 | priv->oldduplex = -1; | ||
| 1763 | 1603 | ||
| 1764 | ugeth->oldlink = 0; | 1604 | snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->ug_info->mdio_bus, |
| 1765 | ugeth->oldspeed = 0; | 1605 | priv->ug_info->phy_address); |
| 1766 | ugeth->oldduplex = -1; | ||
| 1767 | 1606 | ||
| 1768 | mii_info = kmalloc(sizeof(struct ugeth_mii_info), GFP_KERNEL); | 1607 | phydev = phy_connect(dev, phy_id, &adjust_link, 0, priv->phy_interface); |
| 1769 | 1608 | ||
| 1770 | if (NULL == mii_info) { | 1609 | if (IS_ERR(phydev)) { |
| 1771 | ugeth_err("%s: Could not allocate mii_info", dev->name); | 1610 | printk("%s: Could not attach to PHY\n", dev->name); |
| 1772 | return -ENOMEM; | 1611 | return PTR_ERR(phydev); |
| 1773 | } | 1612 | } |
| 1774 | 1613 | ||
| 1775 | mii_info->mii_regs = mii_regs; | 1614 | phydev->supported &= (ADVERTISED_10baseT_Half | |
| 1776 | mii_info->speed = SPEED_1000; | ||
| 1777 | mii_info->duplex = DUPLEX_FULL; | ||
| 1778 | mii_info->pause = 0; | ||
| 1779 | mii_info->link = 0; | ||
| 1780 | |||
| 1781 | mii_info->advertising = (ADVERTISED_10baseT_Half | | ||
| 1782 | ADVERTISED_10baseT_Full | | 1615 | ADVERTISED_10baseT_Full | |
| 1783 | ADVERTISED_100baseT_Half | | 1616 | ADVERTISED_100baseT_Half | |
| 1784 | ADVERTISED_100baseT_Full | | 1617 | ADVERTISED_100baseT_Full); |
| 1785 | ADVERTISED_1000baseT_Full); | ||
| 1786 | mii_info->autoneg = 1; | ||
| 1787 | 1618 | ||
| 1788 | mii_info->mii_id = ugeth->ug_info->phy_address; | 1619 | if (priv->max_speed == SPEED_1000) |
| 1620 | phydev->supported |= ADVERTISED_1000baseT_Full; | ||
| 1789 | 1621 | ||
| 1790 | mii_info->dev = dev; | 1622 | phydev->advertising = phydev->supported; |
| 1791 | 1623 | ||
| 1792 | mii_info->mdio_read = &read_phy_reg; | 1624 | priv->phydev = phydev; |
| 1793 | mii_info->mdio_write = &write_phy_reg; | ||
| 1794 | |||
| 1795 | spin_lock_init(&mii_info->mdio_lock); | ||
| 1796 | |||
| 1797 | ugeth->mii_info = mii_info; | ||
| 1798 | |||
| 1799 | spin_lock_irq(&ugeth->lock); | ||
| 1800 | |||
| 1801 | /* Set this UCC to be the master of the MII managment */ | ||
| 1802 | ucc_set_qe_mux_mii_mng(ugeth->ug_info->uf_info.ucc_num); | ||
| 1803 | |||
| 1804 | if (init_mii_management_configuration(1, | ||
| 1805 | ugeth->ug_info-> | ||
| 1806 | miiPreambleSupress, | ||
| 1807 | &mii_regs->miimcfg, | ||
| 1808 | &mii_regs->miimind)) { | ||
| 1809 | ugeth_err("%s: The MII Bus is stuck!", dev->name); | ||
| 1810 | err = -1; | ||
| 1811 | goto bus_fail; | ||
| 1812 | } | ||
| 1813 | |||
| 1814 | spin_unlock_irq(&ugeth->lock); | ||
| 1815 | |||
| 1816 | /* get info for this PHY */ | ||
| 1817 | curphy = get_phy_info(ugeth->mii_info); | ||
| 1818 | |||
| 1819 | if (curphy == NULL) { | ||
| 1820 | ugeth_err("%s: No PHY found", dev->name); | ||
| 1821 | err = -1; | ||
| 1822 | goto no_phy; | ||
| 1823 | } | ||
| 1824 | |||
| 1825 | mii_info->phyinfo = curphy; | ||
| 1826 | |||
| 1827 | /* Run the commands which initialize the PHY */ | ||
| 1828 | if (curphy->init) { | ||
| 1829 | err = curphy->init(ugeth->mii_info); | ||
| 1830 | if (err) | ||
| 1831 | goto phy_init_fail; | ||
| 1832 | } | ||
| 1833 | 1625 | ||
| 1834 | return 0; | 1626 | return 0; |
| 1835 | |||
| 1836 | phy_init_fail: | ||
| 1837 | no_phy: | ||
| 1838 | bus_fail: | ||
| 1839 | kfree(mii_info); | ||
| 1840 | |||
| 1841 | return err; | ||
| 1842 | } | 1627 | } |
| 1843 | 1628 | ||
| 1844 | #ifdef CONFIG_UGETH_TX_ON_DEMOND | ||
| 1845 | static int ugeth_transmit_on_demand(struct ucc_geth_private *ugeth) | ||
| 1846 | { | ||
| 1847 | struct ucc_fastransmit_on_demand(ugeth->uccf); | ||
| 1848 | 1629 | ||
| 1849 | return 0; | ||
| 1850 | } | ||
| 1851 | #endif | ||
| 1852 | 1630 | ||
| 1853 | static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth) | 1631 | static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth) |
| 1854 | { | 1632 | { |
| @@ -2356,6 +2134,8 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth) | |||
| 2356 | } | 2134 | } |
| 2357 | for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) { | 2135 | for (i = 0; i < ugeth->ug_info->numQueuesTx; i++) { |
| 2358 | bd = ugeth->p_tx_bd_ring[i]; | 2136 | bd = ugeth->p_tx_bd_ring[i]; |
| 2137 | if (!bd) | ||
| 2138 | continue; | ||
| 2359 | for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) { | 2139 | for (j = 0; j < ugeth->ug_info->bdRingLenTx[i]; j++) { |
| 2360 | if (ugeth->tx_skbuff[i][j]) { | 2140 | if (ugeth->tx_skbuff[i][j]) { |
| 2361 | dma_unmap_single(NULL, | 2141 | dma_unmap_single(NULL, |
| @@ -2487,6 +2267,7 @@ static void ucc_geth_set_multi(struct net_device *dev) | |||
| 2487 | static void ucc_geth_stop(struct ucc_geth_private *ugeth) | 2267 | static void ucc_geth_stop(struct ucc_geth_private *ugeth) |
| 2488 | { | 2268 | { |
| 2489 | struct ucc_geth *ug_regs = ugeth->ug_regs; | 2269 | struct ucc_geth *ug_regs = ugeth->ug_regs; |
| 2270 | struct phy_device *phydev = ugeth->phydev; | ||
| 2490 | u32 tempval; | 2271 | u32 tempval; |
| 2491 | 2272 | ||
| 2492 | ugeth_vdbg("%s: IN", __FUNCTION__); | 2273 | ugeth_vdbg("%s: IN", __FUNCTION__); |
| @@ -2495,8 +2276,7 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth) | |||
| 2495 | ugeth_disable(ugeth, COMM_DIR_RX_AND_TX); | 2276 | ugeth_disable(ugeth, COMM_DIR_RX_AND_TX); |
| 2496 | 2277 | ||
| 2497 | /* Tell the kernel the link is down */ | 2278 | /* Tell the kernel the link is down */ |
| 2498 | ugeth->mii_info->link = 0; | 2279 | phy_stop(phydev); |
| 2499 | adjust_link(ugeth->dev); | ||
| 2500 | 2280 | ||
| 2501 | /* Mask all interrupts */ | 2281 | /* Mask all interrupts */ |
| 2502 | out_be32(ugeth->uccf->p_ucce, 0x00000000); | 2282 | out_be32(ugeth->uccf->p_ucce, 0x00000000); |
| @@ -2509,50 +2289,24 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth) | |||
| 2509 | tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX); | 2289 | tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX); |
| 2510 | out_be32(&ug_regs->maccfg1, tempval); | 2290 | out_be32(&ug_regs->maccfg1, tempval); |
| 2511 | 2291 | ||
| 2512 | if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) { | ||
| 2513 | /* Clear any pending interrupts */ | ||
| 2514 | mii_clear_phy_interrupt(ugeth->mii_info); | ||
| 2515 | |||
| 2516 | /* Disable PHY Interrupts */ | ||
| 2517 | mii_configure_phy_interrupt(ugeth->mii_info, | ||
| 2518 | MII_INTERRUPT_DISABLED); | ||
| 2519 | } | ||
| 2520 | |||
| 2521 | free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev); | 2292 | free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev); |
| 2522 | 2293 | ||
| 2523 | if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) { | ||
| 2524 | free_irq(ugeth->ug_info->phy_interrupt, ugeth->dev); | ||
| 2525 | } else { | ||
| 2526 | del_timer_sync(&ugeth->phy_info_timer); | ||
| 2527 | } | ||
| 2528 | |||
| 2529 | ucc_geth_memclean(ugeth); | 2294 | ucc_geth_memclean(ugeth); |
| 2530 | } | 2295 | } |
| 2531 | 2296 | ||
| 2532 | static int ucc_geth_startup(struct ucc_geth_private *ugeth) | 2297 | static int ucc_struct_init(struct ucc_geth_private *ugeth) |
| 2533 | { | 2298 | { |
| 2534 | struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt; | ||
| 2535 | struct ucc_geth_init_pram *p_init_enet_pram; | ||
| 2536 | struct ucc_fast_private *uccf; | ||
| 2537 | struct ucc_geth_info *ug_info; | 2299 | struct ucc_geth_info *ug_info; |
| 2538 | struct ucc_fast_info *uf_info; | 2300 | struct ucc_fast_info *uf_info; |
| 2539 | struct ucc_fast *uf_regs; | 2301 | int i; |
| 2540 | struct ucc_geth *ug_regs; | ||
| 2541 | int ret_val = -EINVAL; | ||
| 2542 | u32 remoder = UCC_GETH_REMODER_INIT; | ||
| 2543 | u32 init_enet_pram_offset, cecr_subblock, command, maccfg1; | ||
| 2544 | u32 ifstat, i, j, size, l2qt, l3qt, length; | ||
| 2545 | u16 temoder = UCC_GETH_TEMODER_INIT; | ||
| 2546 | u16 test; | ||
| 2547 | u8 function_code = 0; | ||
| 2548 | u8 *bd, *endOfRing; | ||
| 2549 | u8 numThreadsRxNumerical, numThreadsTxNumerical; | ||
| 2550 | |||
| 2551 | ugeth_vdbg("%s: IN", __FUNCTION__); | ||
| 2552 | 2302 | ||
| 2553 | ug_info = ugeth->ug_info; | 2303 | ug_info = ugeth->ug_info; |
| 2554 | uf_info = &ug_info->uf_info; | 2304 | uf_info = &ug_info->uf_info; |
| 2555 | 2305 | ||
| 2306 | /* Create CQs for hash tables */ | ||
| 2307 | INIT_LIST_HEAD(&ugeth->group_hash_q); | ||
| 2308 | INIT_LIST_HEAD(&ugeth->ind_hash_q); | ||
| 2309 | |||
| 2556 | if (!((uf_info->bd_mem_part == MEM_PART_SYSTEM) || | 2310 | if (!((uf_info->bd_mem_part == MEM_PART_SYSTEM) || |
| 2557 | (uf_info->bd_mem_part == MEM_PART_MURAM))) { | 2311 | (uf_info->bd_mem_part == MEM_PART_MURAM))) { |
| 2558 | ugeth_err("%s: Bad memory partition value.", __FUNCTION__); | 2312 | ugeth_err("%s: Bad memory partition value.", __FUNCTION__); |
| @@ -2647,12 +2401,42 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) | |||
| 2647 | for (i = 0; i < ug_info->numQueuesTx; i++) | 2401 | for (i = 0; i < ug_info->numQueuesTx; i++) |
| 2648 | uf_info->uccm_mask |= (UCCE_TXBF_SINGLE_MASK << i); | 2402 | uf_info->uccm_mask |= (UCCE_TXBF_SINGLE_MASK << i); |
| 2649 | /* Initialize the general fast UCC block. */ | 2403 | /* Initialize the general fast UCC block. */ |
| 2650 | if (ucc_fast_init(uf_info, &uccf)) { | 2404 | if (ucc_fast_init(uf_info, &ugeth->uccf)) { |
| 2651 | ugeth_err("%s: Failed to init uccf.", __FUNCTION__); | 2405 | ugeth_err("%s: Failed to init uccf.", __FUNCTION__); |
| 2652 | ucc_geth_memclean(ugeth); | 2406 | ucc_geth_memclean(ugeth); |
| 2653 | return -ENOMEM; | 2407 | return -ENOMEM; |
| 2654 | } | 2408 | } |
| 2655 | ugeth->uccf = uccf; | 2409 | |
| 2410 | ugeth->ug_regs = (struct ucc_geth *) ioremap(uf_info->regs, sizeof(struct ucc_geth)); | ||
| 2411 | |||
| 2412 | return 0; | ||
| 2413 | } | ||
| 2414 | |||
| 2415 | static int ucc_geth_startup(struct ucc_geth_private *ugeth) | ||
| 2416 | { | ||
| 2417 | struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt; | ||
| 2418 | struct ucc_geth_init_pram *p_init_enet_pram; | ||
| 2419 | struct ucc_fast_private *uccf; | ||
| 2420 | struct ucc_geth_info *ug_info; | ||
| 2421 | struct ucc_fast_info *uf_info; | ||
| 2422 | struct ucc_fast *uf_regs; | ||
| 2423 | struct ucc_geth *ug_regs; | ||
| 2424 | int ret_val = -EINVAL; | ||
| 2425 | u32 remoder = UCC_GETH_REMODER_INIT; | ||
| 2426 | u32 init_enet_pram_offset, cecr_subblock, command, maccfg1; | ||
| 2427 | u32 ifstat, i, j, size, l2qt, l3qt, length; | ||
| 2428 | u16 temoder = UCC_GETH_TEMODER_INIT; | ||
| 2429 | u16 test; | ||
| 2430 | u8 function_code = 0; | ||
| 2431 | u8 *bd, *endOfRing; | ||
| 2432 | u8 numThreadsRxNumerical, numThreadsTxNumerical; | ||
| 2433 | |||
| 2434 | ugeth_vdbg("%s: IN", __FUNCTION__); | ||
| 2435 | uccf = ugeth->uccf; | ||
| 2436 | ug_info = ugeth->ug_info; | ||
| 2437 | uf_info = &ug_info->uf_info; | ||
| 2438 | uf_regs = uccf->uf_regs; | ||
| 2439 | ug_regs = ugeth->ug_regs; | ||
| 2656 | 2440 | ||
| 2657 | switch (ug_info->numThreadsRx) { | 2441 | switch (ug_info->numThreadsRx) { |
| 2658 | case UCC_GETH_NUM_OF_THREADS_1: | 2442 | case UCC_GETH_NUM_OF_THREADS_1: |
| @@ -2711,10 +2495,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) | |||
| 2711 | || (ug_info->vlanOperationNonTagged != | 2495 | || (ug_info->vlanOperationNonTagged != |
| 2712 | UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP); | 2496 | UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP); |
| 2713 | 2497 | ||
| 2714 | uf_regs = uccf->uf_regs; | ||
| 2715 | ug_regs = (struct ucc_geth *) (uccf->uf_regs); | ||
| 2716 | ugeth->ug_regs = ug_regs; | ||
| 2717 | |||
| 2718 | init_default_reg_vals(&uf_regs->upsmr, | 2498 | init_default_reg_vals(&uf_regs->upsmr, |
| 2719 | &ug_regs->maccfg1, &ug_regs->maccfg2); | 2499 | &ug_regs->maccfg1, &ug_regs->maccfg2); |
| 2720 | 2500 | ||
| @@ -3177,8 +2957,8 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) | |||
| 3177 | /* Size varies with number of Rx queues */ | 2957 | /* Size varies with number of Rx queues */ |
| 3178 | ugeth->rx_irq_coalescing_tbl_offset = | 2958 | ugeth->rx_irq_coalescing_tbl_offset = |
| 3179 | qe_muram_alloc(ug_info->numQueuesRx * | 2959 | qe_muram_alloc(ug_info->numQueuesRx * |
| 3180 | sizeof(struct ucc_geth_rx_interrupt_coalescing_entry), | 2960 | sizeof(struct ucc_geth_rx_interrupt_coalescing_entry) |
| 3181 | UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT); | 2961 | + 4, UCC_GETH_RX_INTERRUPT_COALESCING_ALIGNMENT); |
| 3182 | if (IS_MURAM_ERR(ugeth->rx_irq_coalescing_tbl_offset)) { | 2962 | if (IS_MURAM_ERR(ugeth->rx_irq_coalescing_tbl_offset)) { |
| 3183 | ugeth_err | 2963 | ugeth_err |
| 3184 | ("%s: Can not allocate DPRAM memory for" | 2964 | ("%s: Can not allocate DPRAM memory for" |
| @@ -3359,13 +3139,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) | |||
| 3359 | for (j = 0; j < NUM_OF_PADDRS; j++) | 3139 | for (j = 0; j < NUM_OF_PADDRS; j++) |
| 3360 | ugeth_82xx_filtering_clear_addr_in_paddr(ugeth, (u8) j); | 3140 | ugeth_82xx_filtering_clear_addr_in_paddr(ugeth, (u8) j); |
| 3361 | 3141 | ||
| 3362 | /* Create CQs for hash tables */ | ||
| 3363 | if (ug_info->maxGroupAddrInHash > 0) { | ||
| 3364 | INIT_LIST_HEAD(&ugeth->group_hash_q); | ||
| 3365 | } | ||
| 3366 | if (ug_info->maxIndAddrInHash > 0) { | ||
| 3367 | INIT_LIST_HEAD(&ugeth->ind_hash_q); | ||
| 3368 | } | ||
| 3369 | p_82xx_addr_filt = | 3142 | p_82xx_addr_filt = |
| 3370 | (struct ucc_geth_82xx_address_filtering_pram *) ugeth-> | 3143 | (struct ucc_geth_82xx_address_filtering_pram *) ugeth-> |
| 3371 | p_rx_glbl_pram->addressfiltering; | 3144 | p_rx_glbl_pram->addressfiltering; |
| @@ -3562,6 +3335,9 @@ static void ucc_geth_timeout(struct net_device *dev) | |||
| 3562 | static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) | 3335 | static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) |
| 3563 | { | 3336 | { |
| 3564 | struct ucc_geth_private *ugeth = netdev_priv(dev); | 3337 | struct ucc_geth_private *ugeth = netdev_priv(dev); |
| 3338 | #ifdef CONFIG_UGETH_TX_ON_DEMAND | ||
| 3339 | struct ucc_fast_private *uccf; | ||
| 3340 | #endif | ||
| 3565 | u8 *bd; /* BD pointer */ | 3341 | u8 *bd; /* BD pointer */ |
| 3566 | u32 bd_status; | 3342 | u32 bd_status; |
| 3567 | u8 txQ = 0; | 3343 | u8 txQ = 0; |
| @@ -3620,6 +3396,10 @@ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
| 3620 | out_be16(ugeth->p_cpucount[txQ], ugeth->cpucount[txQ]); | 3396 | out_be16(ugeth->p_cpucount[txQ], ugeth->cpucount[txQ]); |
| 3621 | } | 3397 | } |
| 3622 | 3398 | ||
| 3399 | #ifdef CONFIG_UGETH_TX_ON_DEMAND | ||
| 3400 | uccf = ugeth->uccf; | ||
| 3401 | out_be16(uccf->p_utodr, UCC_FAST_TOD); | ||
| 3402 | #endif | ||
| 3623 | spin_unlock_irq(&ugeth->lock); | 3403 | spin_unlock_irq(&ugeth->lock); |
| 3624 | 3404 | ||
| 3625 | return 0; | 3405 | return 0; |
| @@ -3635,7 +3415,6 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit | |||
| 3635 | 3415 | ||
| 3636 | ugeth_vdbg("%s: IN", __FUNCTION__); | 3416 | ugeth_vdbg("%s: IN", __FUNCTION__); |
| 3637 | 3417 | ||
| 3638 | spin_lock(&ugeth->lock); | ||
| 3639 | /* collect received buffers */ | 3418 | /* collect received buffers */ |
| 3640 | bd = ugeth->rxBd[rxQ]; | 3419 | bd = ugeth->rxBd[rxQ]; |
| 3641 | 3420 | ||
| @@ -3683,7 +3462,6 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit | |||
| 3683 | skb = get_new_skb(ugeth, bd); | 3462 | skb = get_new_skb(ugeth, bd); |
| 3684 | if (!skb) { | 3463 | if (!skb) { |
| 3685 | ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__); | 3464 | ugeth_warn("%s: No Rx Data Buffer", __FUNCTION__); |
| 3686 | spin_unlock(&ugeth->lock); | ||
| 3687 | ugeth->stats.rx_dropped++; | 3465 | ugeth->stats.rx_dropped++; |
| 3688 | break; | 3466 | break; |
| 3689 | } | 3467 | } |
| @@ -3704,7 +3482,6 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit | |||
| 3704 | } | 3482 | } |
| 3705 | 3483 | ||
| 3706 | ugeth->rxBd[rxQ] = bd; | 3484 | ugeth->rxBd[rxQ] = bd; |
| 3707 | spin_unlock(&ugeth->lock); | ||
| 3708 | return howmany; | 3485 | return howmany; |
| 3709 | } | 3486 | } |
| 3710 | 3487 | ||
| @@ -3756,23 +3533,38 @@ static int ucc_geth_tx(struct net_device *dev, u8 txQ) | |||
| 3756 | static int ucc_geth_poll(struct net_device *dev, int *budget) | 3533 | static int ucc_geth_poll(struct net_device *dev, int *budget) |
| 3757 | { | 3534 | { |
| 3758 | struct ucc_geth_private *ugeth = netdev_priv(dev); | 3535 | struct ucc_geth_private *ugeth = netdev_priv(dev); |
| 3536 | struct ucc_geth_info *ug_info; | ||
| 3537 | struct ucc_fast_private *uccf; | ||
| 3759 | int howmany; | 3538 | int howmany; |
| 3760 | int rx_work_limit = *budget; | 3539 | u8 i; |
| 3761 | u8 rxQ = 0; | 3540 | int rx_work_limit; |
| 3541 | register u32 uccm; | ||
| 3542 | |||
| 3543 | ug_info = ugeth->ug_info; | ||
| 3762 | 3544 | ||
| 3545 | rx_work_limit = *budget; | ||
| 3763 | if (rx_work_limit > dev->quota) | 3546 | if (rx_work_limit > dev->quota) |
| 3764 | rx_work_limit = dev->quota; | 3547 | rx_work_limit = dev->quota; |
| 3765 | 3548 | ||
| 3766 | howmany = ucc_geth_rx(ugeth, rxQ, rx_work_limit); | 3549 | howmany = 0; |
| 3550 | |||
| 3551 | for (i = 0; i < ug_info->numQueuesRx; i++) { | ||
| 3552 | howmany += ucc_geth_rx(ugeth, i, rx_work_limit); | ||
| 3553 | } | ||
| 3767 | 3554 | ||
| 3768 | dev->quota -= howmany; | 3555 | dev->quota -= howmany; |
| 3769 | rx_work_limit -= howmany; | 3556 | rx_work_limit -= howmany; |
| 3770 | *budget -= howmany; | 3557 | *budget -= howmany; |
| 3771 | 3558 | ||
| 3772 | if (rx_work_limit >= 0) | 3559 | if (rx_work_limit > 0) { |
| 3773 | netif_rx_complete(dev); | 3560 | netif_rx_complete(dev); |
| 3561 | uccf = ugeth->uccf; | ||
| 3562 | uccm = in_be32(uccf->p_uccm); | ||
| 3563 | uccm |= UCCE_RX_EVENTS; | ||
| 3564 | out_be32(uccf->p_uccm, uccm); | ||
| 3565 | } | ||
| 3774 | 3566 | ||
| 3775 | return (rx_work_limit < 0) ? 1 : 0; | 3567 | return (rx_work_limit > 0) ? 0 : 1; |
| 3776 | } | 3568 | } |
| 3777 | #endif /* CONFIG_UGETH_NAPI */ | 3569 | #endif /* CONFIG_UGETH_NAPI */ |
| 3778 | 3570 | ||
| @@ -3782,10 +3574,13 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) | |||
| 3782 | struct ucc_geth_private *ugeth = netdev_priv(dev); | 3574 | struct ucc_geth_private *ugeth = netdev_priv(dev); |
| 3783 | struct ucc_fast_private *uccf; | 3575 | struct ucc_fast_private *uccf; |
| 3784 | struct ucc_geth_info *ug_info; | 3576 | struct ucc_geth_info *ug_info; |
| 3785 | register u32 ucce = 0; | 3577 | register u32 ucce; |
| 3786 | register u32 bit_mask = UCCE_RXBF_SINGLE_MASK; | 3578 | register u32 uccm; |
| 3787 | register u32 tx_mask = UCCE_TXBF_SINGLE_MASK; | 3579 | #ifndef CONFIG_UGETH_NAPI |
| 3788 | register u8 i; | 3580 | register u32 rx_mask; |
| 3581 | #endif | ||
| 3582 | register u32 tx_mask; | ||
| 3583 | u8 i; | ||
| 3789 | 3584 | ||
| 3790 | ugeth_vdbg("%s: IN", __FUNCTION__); | 3585 | ugeth_vdbg("%s: IN", __FUNCTION__); |
| 3791 | 3586 | ||
| @@ -3795,174 +3590,57 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) | |||
| 3795 | uccf = ugeth->uccf; | 3590 | uccf = ugeth->uccf; |
| 3796 | ug_info = ugeth->ug_info; | 3591 | ug_info = ugeth->ug_info; |
| 3797 | 3592 | ||
| 3798 | do { | 3593 | /* read and clear events */ |
| 3799 | ucce |= (u32) (in_be32(uccf->p_ucce) & in_be32(uccf->p_uccm)); | 3594 | ucce = (u32) in_be32(uccf->p_ucce); |
| 3800 | 3595 | uccm = (u32) in_be32(uccf->p_uccm); | |
| 3801 | /* clear event bits for next time */ | 3596 | ucce &= uccm; |
| 3802 | /* Side effect here is to mask ucce variable | 3597 | out_be32(uccf->p_ucce, ucce); |
| 3803 | for future processing below. */ | ||
| 3804 | out_be32(uccf->p_ucce, ucce); /* Clear with ones, | ||
| 3805 | but only bits in UCCM */ | ||
| 3806 | |||
| 3807 | /* We ignore Tx interrupts because Tx confirmation is | ||
| 3808 | done inside Tx routine */ | ||
| 3809 | 3598 | ||
| 3599 | /* check for receive events that require processing */ | ||
| 3600 | if (ucce & UCCE_RX_EVENTS) { | ||
| 3601 | #ifdef CONFIG_UGETH_NAPI | ||
| 3602 | if (netif_rx_schedule_prep(dev)) { | ||
| 3603 | uccm &= ~UCCE_RX_EVENTS; | ||
| 3604 | out_be32(uccf->p_uccm, uccm); | ||
| 3605 | __netif_rx_schedule(dev); | ||
| 3606 | } | ||
| 3607 | #else | ||
| 3608 | rx_mask = UCCE_RXBF_SINGLE_MASK; | ||
| 3810 | for (i = 0; i < ug_info->numQueuesRx; i++) { | 3609 | for (i = 0; i < ug_info->numQueuesRx; i++) { |
| 3811 | if (ucce & bit_mask) | 3610 | if (ucce & rx_mask) |
| 3812 | ucc_geth_rx(ugeth, i, | 3611 | ucc_geth_rx(ugeth, i, (int)ugeth->ug_info->bdRingLenRx[i]); |
| 3813 | (int)ugeth->ug_info-> | 3612 | ucce &= ~rx_mask; |
| 3814 | bdRingLenRx[i]); | 3613 | rx_mask <<= 1; |
| 3815 | ucce &= ~bit_mask; | ||
| 3816 | bit_mask <<= 1; | ||
| 3817 | } | 3614 | } |
| 3615 | #endif /* CONFIG_UGETH_NAPI */ | ||
| 3616 | } | ||
| 3818 | 3617 | ||
| 3618 | /* Tx event processing */ | ||
| 3619 | if (ucce & UCCE_TX_EVENTS) { | ||
| 3620 | spin_lock(&ugeth->lock); | ||
| 3621 | tx_mask = UCCE_TXBF_SINGLE_MASK; | ||
| 3819 | for (i = 0; i < ug_info->numQueuesTx; i++) { | 3622 | for (i = 0; i < ug_info->numQueuesTx; i++) { |
| 3820 | if (ucce & tx_mask) | 3623 | if (ucce & tx_mask) |
| 3821 | ucc_geth_tx(dev, i); | 3624 | ucc_geth_tx(dev, i); |
| 3822 | ucce &= ~tx_mask; | 3625 | ucce &= ~tx_mask; |
| 3823 | tx_mask <<= 1; | 3626 | tx_mask <<= 1; |
| 3824 | } | 3627 | } |
| 3628 | spin_unlock(&ugeth->lock); | ||
| 3629 | } | ||
| 3825 | 3630 | ||
| 3826 | /* Exceptions */ | 3631 | /* Errors and other events */ |
| 3632 | if (ucce & UCCE_OTHER) { | ||
| 3827 | if (ucce & UCCE_BSY) { | 3633 | if (ucce & UCCE_BSY) { |
| 3828 | ugeth_vdbg("Got BUSY irq!!!!"); | ||
| 3829 | ugeth->stats.rx_errors++; | 3634 | ugeth->stats.rx_errors++; |
| 3830 | ucce &= ~UCCE_BSY; | ||
| 3831 | } | 3635 | } |
| 3832 | if (ucce & UCCE_OTHER) { | 3636 | if (ucce & UCCE_TXE) { |
| 3833 | ugeth_vdbg("Got frame with error (ucce - 0x%08x)!!!!", | 3637 | ugeth->stats.tx_errors++; |
| 3834 | ucce); | ||
| 3835 | ugeth->stats.rx_errors++; | ||
| 3836 | ucce &= ~ucce; | ||
| 3837 | } | 3638 | } |
| 3838 | } | 3639 | } |
| 3839 | while (ucce); | ||
| 3840 | |||
| 3841 | return IRQ_HANDLED; | ||
| 3842 | } | ||
| 3843 | |||
| 3844 | static irqreturn_t phy_interrupt(int irq, void *dev_id) | ||
| 3845 | { | ||
| 3846 | struct net_device *dev = (struct net_device *)dev_id; | ||
| 3847 | struct ucc_geth_private *ugeth = netdev_priv(dev); | ||
| 3848 | |||
| 3849 | ugeth_vdbg("%s: IN", __FUNCTION__); | ||
| 3850 | |||
| 3851 | /* Clear the interrupt */ | ||
| 3852 | mii_clear_phy_interrupt(ugeth->mii_info); | ||
| 3853 | |||
| 3854 | /* Disable PHY interrupts */ | ||
| 3855 | mii_configure_phy_interrupt(ugeth->mii_info, MII_INTERRUPT_DISABLED); | ||
| 3856 | |||
| 3857 | /* Schedule the phy change */ | ||
| 3858 | schedule_work(&ugeth->tq); | ||
| 3859 | 3640 | ||
| 3860 | return IRQ_HANDLED; | 3641 | return IRQ_HANDLED; |
| 3861 | } | 3642 | } |
| 3862 | 3643 | ||
| 3863 | /* Scheduled by the phy_interrupt/timer to handle PHY changes */ | ||
| 3864 | static void ugeth_phy_change(struct work_struct *work) | ||
| 3865 | { | ||
| 3866 | struct ucc_geth_private *ugeth = | ||
| 3867 | container_of(work, struct ucc_geth_private, tq); | ||
| 3868 | struct net_device *dev = ugeth->dev; | ||
| 3869 | struct ucc_geth *ug_regs; | ||
| 3870 | int result = 0; | ||
| 3871 | |||
| 3872 | ugeth_vdbg("%s: IN", __FUNCTION__); | ||
| 3873 | |||
| 3874 | ug_regs = ugeth->ug_regs; | ||
| 3875 | |||
| 3876 | /* Delay to give the PHY a chance to change the | ||
| 3877 | * register state */ | ||
| 3878 | msleep(1); | ||
| 3879 | |||
| 3880 | /* Update the link, speed, duplex */ | ||
| 3881 | result = ugeth->mii_info->phyinfo->read_status(ugeth->mii_info); | ||
| 3882 | |||
| 3883 | /* Adjust the known status as long as the link | ||
| 3884 | * isn't still coming up */ | ||
| 3885 | if ((0 == result) || (ugeth->mii_info->link == 0)) | ||
| 3886 | adjust_link(dev); | ||
| 3887 | |||
| 3888 | /* Reenable interrupts, if needed */ | ||
| 3889 | if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) | ||
| 3890 | mii_configure_phy_interrupt(ugeth->mii_info, | ||
| 3891 | MII_INTERRUPT_ENABLED); | ||
| 3892 | } | ||
| 3893 | |||
| 3894 | /* Called every so often on systems that don't interrupt | ||
| 3895 | * the core for PHY changes */ | ||
| 3896 | static void ugeth_phy_timer(unsigned long data) | ||
| 3897 | { | ||
| 3898 | struct net_device *dev = (struct net_device *)data; | ||
| 3899 | struct ucc_geth_private *ugeth = netdev_priv(dev); | ||
| 3900 | |||
| 3901 | schedule_work(&ugeth->tq); | ||
| 3902 | |||
| 3903 | mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ); | ||
| 3904 | } | ||
| 3905 | |||
| 3906 | /* Keep trying aneg for some time | ||
| 3907 | * If, after GFAR_AN_TIMEOUT seconds, it has not | ||
| 3908 | * finished, we switch to forced. | ||
| 3909 | * Either way, once the process has completed, we either | ||
| 3910 | * request the interrupt, or switch the timer over to | ||
| 3911 | * using ugeth_phy_timer to check status */ | ||
| 3912 | static void ugeth_phy_startup_timer(unsigned long data) | ||
| 3913 | { | ||
| 3914 | struct ugeth_mii_info *mii_info = (struct ugeth_mii_info *)data; | ||
| 3915 | struct ucc_geth_private *ugeth = netdev_priv(mii_info->dev); | ||
| 3916 | static int secondary = UGETH_AN_TIMEOUT; | ||
| 3917 | int result; | ||
| 3918 | |||
| 3919 | /* Configure the Auto-negotiation */ | ||
| 3920 | result = mii_info->phyinfo->config_aneg(mii_info); | ||
| 3921 | |||
| 3922 | /* If autonegotiation failed to start, and | ||
| 3923 | * we haven't timed out, reset the timer, and return */ | ||
| 3924 | if (result && secondary--) { | ||
| 3925 | mod_timer(&ugeth->phy_info_timer, jiffies + HZ); | ||
| 3926 | return; | ||
| 3927 | } else if (result) { | ||
| 3928 | /* Couldn't start autonegotiation. | ||
| 3929 | * Try switching to forced */ | ||
| 3930 | mii_info->autoneg = 0; | ||
| 3931 | result = mii_info->phyinfo->config_aneg(mii_info); | ||
| 3932 | |||
| 3933 | /* Forcing failed! Give up */ | ||
| 3934 | if (result) { | ||
| 3935 | ugeth_err("%s: Forcing failed!", mii_info->dev->name); | ||
| 3936 | return; | ||
| 3937 | } | ||
| 3938 | } | ||
| 3939 | |||
| 3940 | /* Kill the timer so it can be restarted */ | ||
| 3941 | del_timer_sync(&ugeth->phy_info_timer); | ||
| 3942 | |||
| 3943 | /* Grab the PHY interrupt, if necessary/possible */ | ||
| 3944 | if (ugeth->ug_info->board_flags & FSL_UGETH_BRD_HAS_PHY_INTR) { | ||
| 3945 | if (request_irq(ugeth->ug_info->phy_interrupt, | ||
| 3946 | phy_interrupt, IRQF_SHARED, | ||
| 3947 | "phy_interrupt", mii_info->dev) < 0) { | ||
| 3948 | ugeth_err("%s: Can't get IRQ %d (PHY)", | ||
| 3949 | mii_info->dev->name, | ||
| 3950 | ugeth->ug_info->phy_interrupt); | ||
| 3951 | } else { | ||
| 3952 | mii_configure_phy_interrupt(ugeth->mii_info, | ||
| 3953 | MII_INTERRUPT_ENABLED); | ||
| 3954 | return; | ||
| 3955 | } | ||
| 3956 | } | ||
| 3957 | |||
| 3958 | /* Start the timer again, this time in order to | ||
| 3959 | * handle a change in status */ | ||
| 3960 | init_timer(&ugeth->phy_info_timer); | ||
| 3961 | ugeth->phy_info_timer.function = &ugeth_phy_timer; | ||
| 3962 | ugeth->phy_info_timer.data = (unsigned long)mii_info->dev; | ||
| 3963 | mod_timer(&ugeth->phy_info_timer, jiffies + PHY_CHANGE_TIME * HZ); | ||
| 3964 | } | ||
| 3965 | |||
| 3966 | /* Called when something needs to use the ethernet device */ | 3644 | /* Called when something needs to use the ethernet device */ |
| 3967 | /* Returns 0 for success. */ | 3645 | /* Returns 0 for success. */ |
| 3968 | static int ucc_geth_open(struct net_device *dev) | 3646 | static int ucc_geth_open(struct net_device *dev) |
| @@ -3979,6 +3657,12 @@ static int ucc_geth_open(struct net_device *dev) | |||
| 3979 | return -EINVAL; | 3657 | return -EINVAL; |
| 3980 | } | 3658 | } |
| 3981 | 3659 | ||
| 3660 | err = ucc_struct_init(ugeth); | ||
| 3661 | if (err) { | ||
| 3662 | ugeth_err("%s: Cannot configure internal struct, aborting.", dev->name); | ||
| 3663 | return err; | ||
| 3664 | } | ||
| 3665 | |||
| 3982 | err = ucc_geth_startup(ugeth); | 3666 | err = ucc_geth_startup(ugeth); |
| 3983 | if (err) { | 3667 | if (err) { |
| 3984 | ugeth_err("%s: Cannot configure net device, aborting.", | 3668 | ugeth_err("%s: Cannot configure net device, aborting.", |
| @@ -4006,10 +3690,12 @@ static int ucc_geth_open(struct net_device *dev) | |||
| 4006 | 3690 | ||
| 4007 | err = init_phy(dev); | 3691 | err = init_phy(dev); |
| 4008 | if (err) { | 3692 | if (err) { |
| 4009 | ugeth_err("%s: Cannot initialzie PHY, aborting.", dev->name); | 3693 | ugeth_err("%s: Cannot initialize PHY, aborting.", dev->name); |
| 4010 | return err; | 3694 | return err; |
| 4011 | } | 3695 | } |
| 4012 | #ifndef CONFIG_UGETH_NAPI | 3696 | |
| 3697 | phy_start(ugeth->phydev); | ||
| 3698 | |||
| 4013 | err = | 3699 | err = |
| 4014 | request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0, | 3700 | request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0, |
| 4015 | "UCC Geth", dev); | 3701 | "UCC Geth", dev); |
| @@ -4019,15 +3705,6 @@ static int ucc_geth_open(struct net_device *dev) | |||
| 4019 | ucc_geth_stop(ugeth); | 3705 | ucc_geth_stop(ugeth); |
| 4020 | return err; | 3706 | return err; |
| 4021 | } | 3707 | } |
| 4022 | #endif /* CONFIG_UGETH_NAPI */ | ||
| 4023 | |||
| 4024 | /* Set up the PHY change work queue */ | ||
| 4025 | INIT_WORK(&ugeth->tq, ugeth_phy_change); | ||
| 4026 | |||
| 4027 | init_timer(&ugeth->phy_info_timer); | ||
| 4028 | ugeth->phy_info_timer.function = &ugeth_phy_startup_timer; | ||
| 4029 | ugeth->phy_info_timer.data = (unsigned long)ugeth->mii_info; | ||
| 4030 | mod_timer(&ugeth->phy_info_timer, jiffies + HZ); | ||
| 4031 | 3708 | ||
| 4032 | err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); | 3709 | err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); |
| 4033 | if (err) { | 3710 | if (err) { |
| @@ -4050,11 +3727,8 @@ static int ucc_geth_close(struct net_device *dev) | |||
| 4050 | 3727 | ||
| 4051 | ucc_geth_stop(ugeth); | 3728 | ucc_geth_stop(ugeth); |
| 4052 | 3729 | ||
| 4053 | /* Shutdown the PHY */ | 3730 | phy_disconnect(ugeth->phydev); |
| 4054 | if (ugeth->mii_info->phyinfo->close) | 3731 | ugeth->phydev = NULL; |
| 4055 | ugeth->mii_info->phyinfo->close(ugeth->mii_info); | ||
| 4056 | |||
| 4057 | kfree(ugeth->mii_info); | ||
| 4058 | 3732 | ||
| 4059 | netif_stop_queue(dev); | 3733 | netif_stop_queue(dev); |
| 4060 | 3734 | ||
| @@ -4063,20 +3737,53 @@ static int ucc_geth_close(struct net_device *dev) | |||
| 4063 | 3737 | ||
| 4064 | const struct ethtool_ops ucc_geth_ethtool_ops = { }; | 3738 | const struct ethtool_ops ucc_geth_ethtool_ops = { }; |
| 4065 | 3739 | ||
| 3740 | static phy_interface_t to_phy_interface(const char *interface_type) | ||
| 3741 | { | ||
| 3742 | if (strcasecmp(interface_type, "mii") == 0) | ||
| 3743 | return PHY_INTERFACE_MODE_MII; | ||
| 3744 | if (strcasecmp(interface_type, "gmii") == 0) | ||
| 3745 | return PHY_INTERFACE_MODE_GMII; | ||
| 3746 | if (strcasecmp(interface_type, "tbi") == 0) | ||
| 3747 | return PHY_INTERFACE_MODE_TBI; | ||
| 3748 | if (strcasecmp(interface_type, "rmii") == 0) | ||
| 3749 | return PHY_INTERFACE_MODE_RMII; | ||
| 3750 | if (strcasecmp(interface_type, "rgmii") == 0) | ||
| 3751 | return PHY_INTERFACE_MODE_RGMII; | ||
| 3752 | if (strcasecmp(interface_type, "rgmii-id") == 0) | ||
| 3753 | return PHY_INTERFACE_MODE_RGMII_ID; | ||
| 3754 | if (strcasecmp(interface_type, "rtbi") == 0) | ||
| 3755 | return PHY_INTERFACE_MODE_RTBI; | ||
| 3756 | |||
| 3757 | return PHY_INTERFACE_MODE_MII; | ||
| 3758 | } | ||
| 3759 | |||
| 4066 | static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *match) | 3760 | static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *match) |
| 4067 | { | 3761 | { |
| 4068 | struct device *device = &ofdev->dev; | 3762 | struct device *device = &ofdev->dev; |
| 4069 | struct device_node *np = ofdev->node; | 3763 | struct device_node *np = ofdev->node; |
| 3764 | struct device_node *mdio; | ||
| 4070 | struct net_device *dev = NULL; | 3765 | struct net_device *dev = NULL; |
| 4071 | struct ucc_geth_private *ugeth = NULL; | 3766 | struct ucc_geth_private *ugeth = NULL; |
| 4072 | struct ucc_geth_info *ug_info; | 3767 | struct ucc_geth_info *ug_info; |
| 4073 | struct resource res; | 3768 | struct resource res; |
| 4074 | struct device_node *phy; | 3769 | struct device_node *phy; |
| 4075 | int err, ucc_num, phy_interface; | 3770 | int err, ucc_num, max_speed = 0; |
| 4076 | static int mii_mng_configured = 0; | ||
| 4077 | const phandle *ph; | 3771 | const phandle *ph; |
| 4078 | const unsigned int *prop; | 3772 | const unsigned int *prop; |
| 4079 | const void *mac_addr; | 3773 | const void *mac_addr; |
| 3774 | phy_interface_t phy_interface; | ||
| 3775 | static const int enet_to_speed[] = { | ||
| 3776 | SPEED_10, SPEED_10, SPEED_10, | ||
| 3777 | SPEED_100, SPEED_100, SPEED_100, | ||
| 3778 | SPEED_1000, SPEED_1000, SPEED_1000, SPEED_1000, | ||
| 3779 | }; | ||
| 3780 | static const phy_interface_t enet_to_phy_interface[] = { | ||
| 3781 | PHY_INTERFACE_MODE_MII, PHY_INTERFACE_MODE_RMII, | ||
| 3782 | PHY_INTERFACE_MODE_RGMII, PHY_INTERFACE_MODE_MII, | ||
| 3783 | PHY_INTERFACE_MODE_RMII, PHY_INTERFACE_MODE_RGMII, | ||
| 3784 | PHY_INTERFACE_MODE_GMII, PHY_INTERFACE_MODE_RGMII, | ||
| 3785 | PHY_INTERFACE_MODE_TBI, PHY_INTERFACE_MODE_RTBI, | ||
| 3786 | }; | ||
| 4080 | 3787 | ||
| 4081 | ugeth_vdbg("%s: IN", __FUNCTION__); | 3788 | ugeth_vdbg("%s: IN", __FUNCTION__); |
| 4082 | 3789 | ||
| @@ -4087,6 +3794,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
| 4087 | 3794 | ||
| 4088 | ug_info = &ugeth_info[ucc_num]; | 3795 | ug_info = &ugeth_info[ucc_num]; |
| 4089 | ug_info->uf_info.ucc_num = ucc_num; | 3796 | ug_info->uf_info.ucc_num = ucc_num; |
| 3797 | |||
| 4090 | prop = get_property(np, "rx-clock", NULL); | 3798 | prop = get_property(np, "rx-clock", NULL); |
| 4091 | ug_info->uf_info.rx_clock = *prop; | 3799 | ug_info->uf_info.rx_clock = *prop; |
| 4092 | prop = get_property(np, "tx-clock", NULL); | 3800 | prop = get_property(np, "tx-clock", NULL); |
| @@ -4104,13 +3812,72 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
| 4104 | if (phy == NULL) | 3812 | if (phy == NULL) |
| 4105 | return -ENODEV; | 3813 | return -ENODEV; |
| 4106 | 3814 | ||
| 3815 | /* set the PHY address */ | ||
| 4107 | prop = get_property(phy, "reg", NULL); | 3816 | prop = get_property(phy, "reg", NULL); |
| 3817 | if (prop == NULL) | ||
| 3818 | return -1; | ||
| 4108 | ug_info->phy_address = *prop; | 3819 | ug_info->phy_address = *prop; |
| 4109 | prop = get_property(phy, "interface", NULL); | 3820 | |
| 4110 | ug_info->enet_interface = *prop; | 3821 | /* get the phy interface type, or default to MII */ |
| 4111 | ug_info->phy_interrupt = irq_of_parse_and_map(phy, 0); | 3822 | prop = get_property(np, "interface-type", NULL); |
| 4112 | ug_info->board_flags = (ug_info->phy_interrupt == NO_IRQ)? | 3823 | if (!prop) { |
| 4113 | 0:FSL_UGETH_BRD_HAS_PHY_INTR; | 3824 | /* handle interface property present in old trees */ |
| 3825 | prop = get_property(phy, "interface", NULL); | ||
| 3826 | if (prop != NULL) | ||
| 3827 | phy_interface = enet_to_phy_interface[*prop]; | ||
| 3828 | else | ||
| 3829 | phy_interface = PHY_INTERFACE_MODE_MII; | ||
| 3830 | } else { | ||
| 3831 | phy_interface = to_phy_interface((const char *)prop); | ||
| 3832 | } | ||
| 3833 | |||
| 3834 | /* get speed, or derive from interface */ | ||
| 3835 | prop = get_property(np, "max-speed", NULL); | ||
| 3836 | if (!prop) { | ||
| 3837 | /* handle interface property present in old trees */ | ||
| 3838 | prop = get_property(phy, "interface", NULL); | ||
| 3839 | if (prop != NULL) | ||
| 3840 | max_speed = enet_to_speed[*prop]; | ||
| 3841 | } else { | ||
| 3842 | max_speed = *prop; | ||
| 3843 | } | ||
| 3844 | if (!max_speed) { | ||
| 3845 | switch (phy_interface) { | ||
| 3846 | case PHY_INTERFACE_MODE_GMII: | ||
| 3847 | case PHY_INTERFACE_MODE_RGMII: | ||
| 3848 | case PHY_INTERFACE_MODE_RGMII_ID: | ||
| 3849 | case PHY_INTERFACE_MODE_TBI: | ||
| 3850 | case PHY_INTERFACE_MODE_RTBI: | ||
| 3851 | max_speed = SPEED_1000; | ||
| 3852 | break; | ||
| 3853 | default: | ||
| 3854 | max_speed = SPEED_100; | ||
| 3855 | break; | ||
| 3856 | } | ||
| 3857 | } | ||
| 3858 | |||
| 3859 | if (max_speed == SPEED_1000) { | ||
| 3860 | ug_info->uf_info.urfs = UCC_GETH_URFS_GIGA_INIT; | ||
| 3861 | ug_info->uf_info.urfet = UCC_GETH_URFET_GIGA_INIT; | ||
| 3862 | ug_info->uf_info.urfset = UCC_GETH_URFSET_GIGA_INIT; | ||
| 3863 | ug_info->uf_info.utfs = UCC_GETH_UTFS_GIGA_INIT; | ||
| 3864 | ug_info->uf_info.utfet = UCC_GETH_UTFET_GIGA_INIT; | ||
| 3865 | ug_info->uf_info.utftt = UCC_GETH_UTFTT_GIGA_INIT; | ||
| 3866 | } | ||
| 3867 | |||
| 3868 | /* Set the bus id */ | ||
| 3869 | mdio = of_get_parent(phy); | ||
| 3870 | |||
| 3871 | if (mdio == NULL) | ||
| 3872 | return -1; | ||
| 3873 | |||
| 3874 | err = of_address_to_resource(mdio, 0, &res); | ||
| 3875 | of_node_put(mdio); | ||
| 3876 | |||
| 3877 | if (err) | ||
| 3878 | return -1; | ||
| 3879 | |||
| 3880 | ug_info->mdio_bus = res.start; | ||
| 4114 | 3881 | ||
| 4115 | printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d) \n", | 3882 | printk(KERN_INFO "ucc_geth: UCC%1d at 0x%8x (irq = %d) \n", |
| 4116 | ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs, | 3883 | ug_info->uf_info.ucc_num + 1, ug_info->uf_info.regs, |
| @@ -4122,43 +3889,6 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
| 4122 | return -ENODEV; | 3889 | return -ENODEV; |
| 4123 | } | 3890 | } |
| 4124 | 3891 | ||
| 4125 | /* FIXME: Work around for early chip rev. */ | ||
| 4126 | /* There's a bug in initial chip rev(s) in the RGMII ac */ | ||
| 4127 | /* timing. */ | ||
| 4128 | /* The following compensates by writing to the reserved */ | ||
| 4129 | /* QE Port Output Hold Registers (CPOH1?). */ | ||
| 4130 | prop = get_property(phy, "interface", NULL); | ||
| 4131 | phy_interface = *prop; | ||
| 4132 | if ((phy_interface == ENET_1000_RGMII) || | ||
| 4133 | (phy_interface == ENET_100_RGMII) || | ||
| 4134 | (phy_interface == ENET_10_RGMII)) { | ||
| 4135 | struct device_node *soc; | ||
| 4136 | phys_addr_t immrbase = -1; | ||
| 4137 | u32 *tmp_reg; | ||
| 4138 | u32 tmp_val; | ||
| 4139 | |||
| 4140 | soc = of_find_node_by_type(NULL, "soc"); | ||
| 4141 | if (soc) { | ||
| 4142 | unsigned int size; | ||
| 4143 | const void *prop = get_property(soc, "reg", &size); | ||
| 4144 | immrbase = of_translate_address(soc, prop); | ||
| 4145 | of_node_put(soc); | ||
| 4146 | }; | ||
| 4147 | |||
| 4148 | tmp_reg = (u32 *) ioremap(immrbase + 0x14A8, 0x4); | ||
| 4149 | tmp_val = in_be32(tmp_reg); | ||
| 4150 | if (ucc_num == 1) | ||
| 4151 | out_be32(tmp_reg, tmp_val | 0x00003000); | ||
| 4152 | else if (ucc_num == 2) | ||
| 4153 | out_be32(tmp_reg, tmp_val | 0x0c000000); | ||
| 4154 | iounmap(tmp_reg); | ||
| 4155 | } | ||
| 4156 | |||
| 4157 | if (!mii_mng_configured) { | ||
| 4158 | ucc_set_qe_mux_mii_mng(ucc_num); | ||
| 4159 | mii_mng_configured = 1; | ||
| 4160 | } | ||
| 4161 | |||
| 4162 | /* Create an ethernet device instance */ | 3892 | /* Create an ethernet device instance */ |
| 4163 | dev = alloc_etherdev(sizeof(*ugeth)); | 3893 | dev = alloc_etherdev(sizeof(*ugeth)); |
| 4164 | 3894 | ||
| @@ -4192,6 +3922,10 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
| 4192 | dev->set_multicast_list = ucc_geth_set_multi; | 3922 | dev->set_multicast_list = ucc_geth_set_multi; |
| 4193 | dev->ethtool_ops = &ucc_geth_ethtool_ops; | 3923 | dev->ethtool_ops = &ucc_geth_ethtool_ops; |
| 4194 | 3924 | ||
| 3925 | ugeth->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1; | ||
| 3926 | ugeth->phy_interface = phy_interface; | ||
| 3927 | ugeth->max_speed = max_speed; | ||
| 3928 | |||
| 4195 | err = register_netdev(dev); | 3929 | err = register_netdev(dev); |
| 4196 | if (err) { | 3930 | if (err) { |
| 4197 | ugeth_err("%s: Cannot register net device, aborting.", | 3931 | ugeth_err("%s: Cannot register net device, aborting.", |
| @@ -4200,13 +3934,13 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma | |||
| 4200 | return err; | 3934 | return err; |
| 4201 | } | 3935 | } |
| 4202 | 3936 | ||
| 4203 | ugeth->ug_info = ug_info; | ||
| 4204 | ugeth->dev = dev; | ||
| 4205 | |||
| 4206 | mac_addr = of_get_mac_address(np); | 3937 | mac_addr = of_get_mac_address(np); |
| 4207 | if (mac_addr) | 3938 | if (mac_addr) |
| 4208 | memcpy(dev->dev_addr, mac_addr, 6); | 3939 | memcpy(dev->dev_addr, mac_addr, 6); |
| 4209 | 3940 | ||
| 3941 | ugeth->ug_info = ug_info; | ||
| 3942 | ugeth->dev = dev; | ||
| 3943 | |||
| 4210 | return 0; | 3944 | return 0; |
| 4211 | } | 3945 | } |
| 4212 | 3946 | ||
| @@ -4242,19 +3976,30 @@ static struct of_platform_driver ucc_geth_driver = { | |||
| 4242 | 3976 | ||
| 4243 | static int __init ucc_geth_init(void) | 3977 | static int __init ucc_geth_init(void) |
| 4244 | { | 3978 | { |
| 4245 | int i; | 3979 | int i, ret; |
| 3980 | |||
| 3981 | ret = uec_mdio_init(); | ||
| 3982 | |||
| 3983 | if (ret) | ||
| 3984 | return ret; | ||
| 4246 | 3985 | ||
| 4247 | printk(KERN_INFO "ucc_geth: " DRV_DESC "\n"); | 3986 | printk(KERN_INFO "ucc_geth: " DRV_DESC "\n"); |
| 4248 | for (i = 0; i < 8; i++) | 3987 | for (i = 0; i < 8; i++) |
| 4249 | memcpy(&(ugeth_info[i]), &ugeth_primary_info, | 3988 | memcpy(&(ugeth_info[i]), &ugeth_primary_info, |
| 4250 | sizeof(ugeth_primary_info)); | 3989 | sizeof(ugeth_primary_info)); |
| 4251 | 3990 | ||
| 4252 | return of_register_platform_driver(&ucc_geth_driver); | 3991 | ret = of_register_platform_driver(&ucc_geth_driver); |
| 3992 | |||
| 3993 | if (ret) | ||
| 3994 | uec_mdio_exit(); | ||
| 3995 | |||
| 3996 | return ret; | ||
| 4253 | } | 3997 | } |
| 4254 | 3998 | ||
| 4255 | static void __exit ucc_geth_exit(void) | 3999 | static void __exit ucc_geth_exit(void) |
| 4256 | { | 4000 | { |
| 4257 | of_unregister_platform_driver(&ucc_geth_driver); | 4001 | of_unregister_platform_driver(&ucc_geth_driver); |
| 4002 | uec_mdio_exit(); | ||
| 4258 | } | 4003 | } |
| 4259 | 4004 | ||
| 4260 | module_init(ucc_geth_init); | 4005 | module_init(ucc_geth_init); |
| @@ -4262,4 +4007,5 @@ module_exit(ucc_geth_exit); | |||
| 4262 | 4007 | ||
| 4263 | MODULE_AUTHOR("Freescale Semiconductor, Inc"); | 4008 | MODULE_AUTHOR("Freescale Semiconductor, Inc"); |
| 4264 | MODULE_DESCRIPTION(DRV_DESC); | 4009 | MODULE_DESCRIPTION(DRV_DESC); |
| 4010 | MODULE_VERSION(DRV_VERSION); | ||
| 4265 | MODULE_LICENSE("GPL"); | 4011 | MODULE_LICENSE("GPL"); |
