diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2008-10-06 20:15:07 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2008-10-06 20:15:07 -0400 |
commit | fa6428ebfa2197841902b89cbc25334707e2f6eb (patch) | |
tree | d139b822bc5447198528defb29f0c0e90d89651c /drivers/net | |
parent | c9b59da130b4430910e02a80816f317534cd5e53 (diff) | |
parent | 3d5fa877bdf65451c78c3b3d581355deea403b80 (diff) |
Merge commit 'jwb/jwb-next'
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/ibm_newemac/Kconfig | 12 | ||||
-rw-r--r-- | drivers/net/ibm_newemac/core.c | 60 | ||||
-rw-r--r-- | drivers/net/ibm_newemac/core.h | 11 | ||||
-rw-r--r-- | drivers/net/ibm_newemac/mal.c | 60 | ||||
-rw-r--r-- | drivers/net/ibm_newemac/mal.h | 34 | ||||
-rw-r--r-- | drivers/net/ibm_newemac/phy.c | 84 | ||||
-rw-r--r-- | drivers/net/ibm_newemac/phy.h | 2 |
7 files changed, 249 insertions, 14 deletions
diff --git a/drivers/net/ibm_newemac/Kconfig b/drivers/net/ibm_newemac/Kconfig index 70a3272ee998..44e5a0e9922a 100644 --- a/drivers/net/ibm_newemac/Kconfig +++ b/drivers/net/ibm_newemac/Kconfig | |||
@@ -62,3 +62,15 @@ config IBM_NEW_EMAC_TAH | |||
62 | config IBM_NEW_EMAC_EMAC4 | 62 | config IBM_NEW_EMAC_EMAC4 |
63 | bool | 63 | bool |
64 | default n | 64 | default n |
65 | |||
66 | config IBM_NEW_EMAC_NO_FLOW_CTRL | ||
67 | bool | ||
68 | default n | ||
69 | |||
70 | config IBM_NEW_EMAC_MAL_CLR_ICINTSTAT | ||
71 | bool | ||
72 | default n | ||
73 | |||
74 | config IBM_NEW_EMAC_MAL_COMMON_ERR | ||
75 | bool | ||
76 | default n | ||
diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index ccd9d9058f6d..efcf21c9f5c7 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c | |||
@@ -130,6 +130,7 @@ static inline void emac_report_timeout_error(struct emac_instance *dev, | |||
130 | const char *error) | 130 | const char *error) |
131 | { | 131 | { |
132 | if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX | | 132 | if (emac_has_feature(dev, EMAC_FTR_440GX_PHY_CLK_FIX | |
133 | EMAC_FTR_460EX_PHY_CLK_FIX | | ||
133 | EMAC_FTR_440EP_PHY_CLK_FIX)) | 134 | EMAC_FTR_440EP_PHY_CLK_FIX)) |
134 | DBG(dev, "%s" NL, error); | 135 | DBG(dev, "%s" NL, error); |
135 | else if (net_ratelimit()) | 136 | else if (net_ratelimit()) |
@@ -201,13 +202,15 @@ static inline int emac_phy_supports_gige(int phy_mode) | |||
201 | { | 202 | { |
202 | return phy_mode == PHY_MODE_GMII || | 203 | return phy_mode == PHY_MODE_GMII || |
203 | phy_mode == PHY_MODE_RGMII || | 204 | phy_mode == PHY_MODE_RGMII || |
205 | phy_mode == PHY_MODE_SGMII || | ||
204 | phy_mode == PHY_MODE_TBI || | 206 | phy_mode == PHY_MODE_TBI || |
205 | phy_mode == PHY_MODE_RTBI; | 207 | phy_mode == PHY_MODE_RTBI; |
206 | } | 208 | } |
207 | 209 | ||
208 | static inline int emac_phy_gpcs(int phy_mode) | 210 | static inline int emac_phy_gpcs(int phy_mode) |
209 | { | 211 | { |
210 | return phy_mode == PHY_MODE_TBI || | 212 | return phy_mode == PHY_MODE_SGMII || |
213 | phy_mode == PHY_MODE_TBI || | ||
211 | phy_mode == PHY_MODE_RTBI; | 214 | phy_mode == PHY_MODE_RTBI; |
212 | } | 215 | } |
213 | 216 | ||
@@ -351,10 +354,24 @@ static int emac_reset(struct emac_instance *dev) | |||
351 | emac_tx_disable(dev); | 354 | emac_tx_disable(dev); |
352 | } | 355 | } |
353 | 356 | ||
357 | #ifdef CONFIG_PPC_DCR_NATIVE | ||
358 | /* Enable internal clock source */ | ||
359 | if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) | ||
360 | dcri_clrset(SDR0, SDR0_ETH_CFG, | ||
361 | 0, SDR0_ETH_CFG_ECS << dev->cell_index); | ||
362 | #endif | ||
363 | |||
354 | out_be32(&p->mr0, EMAC_MR0_SRST); | 364 | out_be32(&p->mr0, EMAC_MR0_SRST); |
355 | while ((in_be32(&p->mr0) & EMAC_MR0_SRST) && n) | 365 | while ((in_be32(&p->mr0) & EMAC_MR0_SRST) && n) |
356 | --n; | 366 | --n; |
357 | 367 | ||
368 | #ifdef CONFIG_PPC_DCR_NATIVE | ||
369 | /* Enable external clock source */ | ||
370 | if (emac_has_feature(dev, EMAC_FTR_460EX_PHY_CLK_FIX)) | ||
371 | dcri_clrset(SDR0, SDR0_ETH_CFG, | ||
372 | SDR0_ETH_CFG_ECS << dev->cell_index, 0); | ||
373 | #endif | ||
374 | |||
358 | if (n) { | 375 | if (n) { |
359 | dev->reset_failed = 0; | 376 | dev->reset_failed = 0; |
360 | return 0; | 377 | return 0; |
@@ -547,8 +564,9 @@ static int emac_configure(struct emac_instance *dev) | |||
547 | switch (dev->phy.speed) { | 564 | switch (dev->phy.speed) { |
548 | case SPEED_1000: | 565 | case SPEED_1000: |
549 | if (emac_phy_gpcs(dev->phy.mode)) { | 566 | if (emac_phy_gpcs(dev->phy.mode)) { |
550 | mr1 |= EMAC_MR1_MF_1000GPCS | | 567 | mr1 |= EMAC_MR1_MF_1000GPCS | EMAC_MR1_MF_IPPA( |
551 | EMAC_MR1_MF_IPPA(dev->phy.address); | 568 | (dev->phy.gpcs_address != 0xffffffff) ? |
569 | dev->phy.gpcs_address : dev->phy.address); | ||
552 | 570 | ||
553 | /* Put some arbitrary OUI, Manuf & Rev IDs so we can | 571 | /* Put some arbitrary OUI, Manuf & Rev IDs so we can |
554 | * identify this GPCS PHY later. | 572 | * identify this GPCS PHY later. |
@@ -660,8 +678,12 @@ static int emac_configure(struct emac_instance *dev) | |||
660 | out_be32(&p->iser, r); | 678 | out_be32(&p->iser, r); |
661 | 679 | ||
662 | /* We need to take GPCS PHY out of isolate mode after EMAC reset */ | 680 | /* We need to take GPCS PHY out of isolate mode after EMAC reset */ |
663 | if (emac_phy_gpcs(dev->phy.mode)) | 681 | if (emac_phy_gpcs(dev->phy.mode)) { |
664 | emac_mii_reset_phy(&dev->phy); | 682 | if (dev->phy.gpcs_address != 0xffffffff) |
683 | emac_mii_reset_gpcs(&dev->phy); | ||
684 | else | ||
685 | emac_mii_reset_phy(&dev->phy); | ||
686 | } | ||
665 | 687 | ||
666 | return 0; | 688 | return 0; |
667 | } | 689 | } |
@@ -866,7 +888,9 @@ static int emac_mdio_read(struct net_device *ndev, int id, int reg) | |||
866 | struct emac_instance *dev = netdev_priv(ndev); | 888 | struct emac_instance *dev = netdev_priv(ndev); |
867 | int res; | 889 | int res; |
868 | 890 | ||
869 | res = __emac_mdio_read(dev->mdio_instance ? dev->mdio_instance : dev, | 891 | res = __emac_mdio_read((dev->mdio_instance && |
892 | dev->phy.gpcs_address != id) ? | ||
893 | dev->mdio_instance : dev, | ||
870 | (u8) id, (u8) reg); | 894 | (u8) id, (u8) reg); |
871 | return res; | 895 | return res; |
872 | } | 896 | } |
@@ -875,7 +899,9 @@ static void emac_mdio_write(struct net_device *ndev, int id, int reg, int val) | |||
875 | { | 899 | { |
876 | struct emac_instance *dev = netdev_priv(ndev); | 900 | struct emac_instance *dev = netdev_priv(ndev); |
877 | 901 | ||
878 | __emac_mdio_write(dev->mdio_instance ? dev->mdio_instance : dev, | 902 | __emac_mdio_write((dev->mdio_instance && |
903 | dev->phy.gpcs_address != id) ? | ||
904 | dev->mdio_instance : dev, | ||
879 | (u8) id, (u8) reg, (u16) val); | 905 | (u8) id, (u8) reg, (u16) val); |
880 | } | 906 | } |
881 | 907 | ||
@@ -2367,7 +2393,11 @@ static int __devinit emac_init_phy(struct emac_instance *dev) | |||
2367 | * XXX I probably should move these settings to the dev tree | 2393 | * XXX I probably should move these settings to the dev tree |
2368 | */ | 2394 | */ |
2369 | dev->phy.address = -1; | 2395 | dev->phy.address = -1; |
2370 | dev->phy.features = SUPPORTED_100baseT_Full | SUPPORTED_MII; | 2396 | dev->phy.features = SUPPORTED_MII; |
2397 | if (emac_phy_supports_gige(dev->phy_mode)) | ||
2398 | dev->phy.features |= SUPPORTED_1000baseT_Full; | ||
2399 | else | ||
2400 | dev->phy.features |= SUPPORTED_100baseT_Full; | ||
2371 | dev->phy.pause = 1; | 2401 | dev->phy.pause = 1; |
2372 | 2402 | ||
2373 | return 0; | 2403 | return 0; |
@@ -2406,7 +2436,9 @@ static int __devinit emac_init_phy(struct emac_instance *dev) | |||
2406 | * Note that the busy_phy_map is currently global | 2436 | * Note that the busy_phy_map is currently global |
2407 | * while it should probably be per-ASIC... | 2437 | * while it should probably be per-ASIC... |
2408 | */ | 2438 | */ |
2409 | dev->phy.address = dev->cell_index; | 2439 | dev->phy.gpcs_address = dev->gpcs_address; |
2440 | if (dev->phy.gpcs_address == 0xffffffff) | ||
2441 | dev->phy.address = dev->cell_index; | ||
2410 | } | 2442 | } |
2411 | 2443 | ||
2412 | emac_configure(dev); | 2444 | emac_configure(dev); |
@@ -2516,6 +2548,8 @@ static int __devinit emac_init_config(struct emac_instance *dev) | |||
2516 | dev->phy_address = 0xffffffff; | 2548 | dev->phy_address = 0xffffffff; |
2517 | if (emac_read_uint_prop(np, "phy-map", &dev->phy_map, 0)) | 2549 | if (emac_read_uint_prop(np, "phy-map", &dev->phy_map, 0)) |
2518 | dev->phy_map = 0xffffffff; | 2550 | dev->phy_map = 0xffffffff; |
2551 | if (emac_read_uint_prop(np, "gpcs-address", &dev->gpcs_address, 0)) | ||
2552 | dev->gpcs_address = 0xffffffff; | ||
2519 | if (emac_read_uint_prop(np->parent, "clock-frequency", &dev->opb_bus_freq, 1)) | 2553 | if (emac_read_uint_prop(np->parent, "clock-frequency", &dev->opb_bus_freq, 1)) |
2520 | return -ENXIO; | 2554 | return -ENXIO; |
2521 | if (emac_read_uint_prop(np, "tah-device", &dev->tah_ph, 0)) | 2555 | if (emac_read_uint_prop(np, "tah-device", &dev->tah_ph, 0)) |
@@ -2559,6 +2593,9 @@ static int __devinit emac_init_config(struct emac_instance *dev) | |||
2559 | /* Check EMAC version */ | 2593 | /* Check EMAC version */ |
2560 | if (of_device_is_compatible(np, "ibm,emac4sync")) { | 2594 | if (of_device_is_compatible(np, "ibm,emac4sync")) { |
2561 | dev->features |= (EMAC_FTR_EMAC4 | EMAC_FTR_EMAC4SYNC); | 2595 | dev->features |= (EMAC_FTR_EMAC4 | EMAC_FTR_EMAC4SYNC); |
2596 | if (of_device_is_compatible(np, "ibm,emac-460ex") || | ||
2597 | of_device_is_compatible(np, "ibm,emac-460gt")) | ||
2598 | dev->features |= EMAC_FTR_460EX_PHY_CLK_FIX; | ||
2562 | } else if (of_device_is_compatible(np, "ibm,emac4")) { | 2599 | } else if (of_device_is_compatible(np, "ibm,emac4")) { |
2563 | dev->features |= EMAC_FTR_EMAC4; | 2600 | dev->features |= EMAC_FTR_EMAC4; |
2564 | if (of_device_is_compatible(np, "ibm,emac-440gx")) | 2601 | if (of_device_is_compatible(np, "ibm,emac-440gx")) |
@@ -2567,6 +2604,8 @@ static int __devinit emac_init_config(struct emac_instance *dev) | |||
2567 | if (of_device_is_compatible(np, "ibm,emac-440ep") || | 2604 | if (of_device_is_compatible(np, "ibm,emac-440ep") || |
2568 | of_device_is_compatible(np, "ibm,emac-440gr")) | 2605 | of_device_is_compatible(np, "ibm,emac-440gr")) |
2569 | dev->features |= EMAC_FTR_440EP_PHY_CLK_FIX; | 2606 | dev->features |= EMAC_FTR_440EP_PHY_CLK_FIX; |
2607 | if (of_device_is_compatible(np, "ibm,emac-405ez")) | ||
2608 | dev->features |= EMAC_FTR_NO_FLOW_CONTROL_40x; | ||
2570 | } | 2609 | } |
2571 | 2610 | ||
2572 | /* Fixup some feature bits based on the device tree */ | 2611 | /* Fixup some feature bits based on the device tree */ |
@@ -2824,6 +2863,9 @@ static int __devinit emac_probe(struct of_device *ofdev, | |||
2824 | ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], | 2863 | ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], |
2825 | ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); | 2864 | ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); |
2826 | 2865 | ||
2866 | if (dev->phy_mode == PHY_MODE_SGMII) | ||
2867 | printk(KERN_NOTICE "%s: in SGMII mode\n", ndev->name); | ||
2868 | |||
2827 | if (dev->phy.address >= 0) | 2869 | if (dev->phy.address >= 0) |
2828 | printk("%s: found %s PHY (0x%02x)\n", ndev->name, | 2870 | printk("%s: found %s PHY (0x%02x)\n", ndev->name, |
2829 | dev->phy.def->name, dev->phy.address); | 2871 | dev->phy.def->name, dev->phy.address); |
diff --git a/drivers/net/ibm_newemac/core.h b/drivers/net/ibm_newemac/core.h index 6545e69d12c3..18d56c6c4238 100644 --- a/drivers/net/ibm_newemac/core.h +++ b/drivers/net/ibm_newemac/core.h | |||
@@ -190,6 +190,9 @@ struct emac_instance { | |||
190 | struct delayed_work link_work; | 190 | struct delayed_work link_work; |
191 | int link_polling; | 191 | int link_polling; |
192 | 192 | ||
193 | /* GPCS PHY infos */ | ||
194 | u32 gpcs_address; | ||
195 | |||
193 | /* Shared MDIO if any */ | 196 | /* Shared MDIO if any */ |
194 | u32 mdio_ph; | 197 | u32 mdio_ph; |
195 | struct of_device *mdio_dev; | 198 | struct of_device *mdio_dev; |
@@ -317,6 +320,10 @@ struct emac_instance { | |||
317 | * The 405EX and 460EX contain the EMAC4SYNC core | 320 | * The 405EX and 460EX contain the EMAC4SYNC core |
318 | */ | 321 | */ |
319 | #define EMAC_FTR_EMAC4SYNC 0x00000200 | 322 | #define EMAC_FTR_EMAC4SYNC 0x00000200 |
323 | /* | ||
324 | * Set if we need phy clock workaround for 460ex or 460gt | ||
325 | */ | ||
326 | #define EMAC_FTR_460EX_PHY_CLK_FIX 0x00000400 | ||
320 | 327 | ||
321 | 328 | ||
322 | /* Right now, we don't quite handle the always/possible masks on the | 329 | /* Right now, we don't quite handle the always/possible masks on the |
@@ -341,6 +348,10 @@ enum { | |||
341 | #ifdef CONFIG_IBM_NEW_EMAC_RGMII | 348 | #ifdef CONFIG_IBM_NEW_EMAC_RGMII |
342 | EMAC_FTR_HAS_RGMII | | 349 | EMAC_FTR_HAS_RGMII | |
343 | #endif | 350 | #endif |
351 | #ifdef CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL | ||
352 | EMAC_FTR_NO_FLOW_CONTROL_40x | | ||
353 | #endif | ||
354 | EMAC_FTR_460EX_PHY_CLK_FIX | | ||
344 | EMAC_FTR_440EP_PHY_CLK_FIX, | 355 | EMAC_FTR_440EP_PHY_CLK_FIX, |
345 | }; | 356 | }; |
346 | 357 | ||
diff --git a/drivers/net/ibm_newemac/mal.c b/drivers/net/ibm_newemac/mal.c index 10c267b2b961..1839d3f154a3 100644 --- a/drivers/net/ibm_newemac/mal.c +++ b/drivers/net/ibm_newemac/mal.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/delay.h> | 28 | #include <linux/delay.h> |
29 | 29 | ||
30 | #include "core.h" | 30 | #include "core.h" |
31 | #include <asm/dcr-regs.h> | ||
31 | 32 | ||
32 | static int mal_count; | 33 | static int mal_count; |
33 | 34 | ||
@@ -279,6 +280,10 @@ static irqreturn_t mal_txeob(int irq, void *dev_instance) | |||
279 | mal_schedule_poll(mal); | 280 | mal_schedule_poll(mal); |
280 | set_mal_dcrn(mal, MAL_TXEOBISR, r); | 281 | set_mal_dcrn(mal, MAL_TXEOBISR, r); |
281 | 282 | ||
283 | if (mal_has_feature(mal, MAL_FTR_CLEAR_ICINTSTAT)) | ||
284 | mtdcri(SDR0, DCRN_SDR_ICINTSTAT, | ||
285 | (mfdcri(SDR0, DCRN_SDR_ICINTSTAT) | ICINTSTAT_ICTX)); | ||
286 | |||
282 | return IRQ_HANDLED; | 287 | return IRQ_HANDLED; |
283 | } | 288 | } |
284 | 289 | ||
@@ -293,6 +298,10 @@ static irqreturn_t mal_rxeob(int irq, void *dev_instance) | |||
293 | mal_schedule_poll(mal); | 298 | mal_schedule_poll(mal); |
294 | set_mal_dcrn(mal, MAL_RXEOBISR, r); | 299 | set_mal_dcrn(mal, MAL_RXEOBISR, r); |
295 | 300 | ||
301 | if (mal_has_feature(mal, MAL_FTR_CLEAR_ICINTSTAT)) | ||
302 | mtdcri(SDR0, DCRN_SDR_ICINTSTAT, | ||
303 | (mfdcri(SDR0, DCRN_SDR_ICINTSTAT) | ICINTSTAT_ICRX)); | ||
304 | |||
296 | return IRQ_HANDLED; | 305 | return IRQ_HANDLED; |
297 | } | 306 | } |
298 | 307 | ||
@@ -336,6 +345,25 @@ static irqreturn_t mal_rxde(int irq, void *dev_instance) | |||
336 | return IRQ_HANDLED; | 345 | return IRQ_HANDLED; |
337 | } | 346 | } |
338 | 347 | ||
348 | static irqreturn_t mal_int(int irq, void *dev_instance) | ||
349 | { | ||
350 | struct mal_instance *mal = dev_instance; | ||
351 | u32 esr = get_mal_dcrn(mal, MAL_ESR); | ||
352 | |||
353 | if (esr & MAL_ESR_EVB) { | ||
354 | /* descriptor error */ | ||
355 | if (esr & MAL_ESR_DE) { | ||
356 | if (esr & MAL_ESR_CIDT) | ||
357 | return mal_rxde(irq, dev_instance); | ||
358 | else | ||
359 | return mal_txde(irq, dev_instance); | ||
360 | } else { /* SERR */ | ||
361 | return mal_serr(irq, dev_instance); | ||
362 | } | ||
363 | } | ||
364 | return IRQ_HANDLED; | ||
365 | } | ||
366 | |||
339 | void mal_poll_disable(struct mal_instance *mal, struct mal_commac *commac) | 367 | void mal_poll_disable(struct mal_instance *mal, struct mal_commac *commac) |
340 | { | 368 | { |
341 | /* Spinlock-type semantics: only one caller disable poll at a time */ | 369 | /* Spinlock-type semantics: only one caller disable poll at a time */ |
@@ -493,6 +521,8 @@ static int __devinit mal_probe(struct of_device *ofdev, | |||
493 | unsigned int dcr_base; | 521 | unsigned int dcr_base; |
494 | const u32 *prop; | 522 | const u32 *prop; |
495 | u32 cfg; | 523 | u32 cfg; |
524 | unsigned long irqflags; | ||
525 | irq_handler_t hdlr_serr, hdlr_txde, hdlr_rxde; | ||
496 | 526 | ||
497 | mal = kzalloc(sizeof(struct mal_instance), GFP_KERNEL); | 527 | mal = kzalloc(sizeof(struct mal_instance), GFP_KERNEL); |
498 | if (!mal) { | 528 | if (!mal) { |
@@ -542,11 +572,21 @@ static int __devinit mal_probe(struct of_device *ofdev, | |||
542 | goto fail; | 572 | goto fail; |
543 | } | 573 | } |
544 | 574 | ||
575 | if (of_device_is_compatible(ofdev->node, "ibm,mcmal-405ez")) | ||
576 | mal->features |= (MAL_FTR_CLEAR_ICINTSTAT | | ||
577 | MAL_FTR_COMMON_ERR_INT); | ||
578 | |||
545 | mal->txeob_irq = irq_of_parse_and_map(ofdev->node, 0); | 579 | mal->txeob_irq = irq_of_parse_and_map(ofdev->node, 0); |
546 | mal->rxeob_irq = irq_of_parse_and_map(ofdev->node, 1); | 580 | mal->rxeob_irq = irq_of_parse_and_map(ofdev->node, 1); |
547 | mal->serr_irq = irq_of_parse_and_map(ofdev->node, 2); | 581 | mal->serr_irq = irq_of_parse_and_map(ofdev->node, 2); |
548 | mal->txde_irq = irq_of_parse_and_map(ofdev->node, 3); | 582 | |
549 | mal->rxde_irq = irq_of_parse_and_map(ofdev->node, 4); | 583 | if (mal_has_feature(mal, MAL_FTR_COMMON_ERR_INT)) { |
584 | mal->txde_irq = mal->rxde_irq = mal->serr_irq; | ||
585 | } else { | ||
586 | mal->txde_irq = irq_of_parse_and_map(ofdev->node, 3); | ||
587 | mal->rxde_irq = irq_of_parse_and_map(ofdev->node, 4); | ||
588 | } | ||
589 | |||
550 | if (mal->txeob_irq == NO_IRQ || mal->rxeob_irq == NO_IRQ || | 590 | if (mal->txeob_irq == NO_IRQ || mal->rxeob_irq == NO_IRQ || |
551 | mal->serr_irq == NO_IRQ || mal->txde_irq == NO_IRQ || | 591 | mal->serr_irq == NO_IRQ || mal->txde_irq == NO_IRQ || |
552 | mal->rxde_irq == NO_IRQ) { | 592 | mal->rxde_irq == NO_IRQ) { |
@@ -608,16 +648,26 @@ static int __devinit mal_probe(struct of_device *ofdev, | |||
608 | sizeof(struct mal_descriptor) * | 648 | sizeof(struct mal_descriptor) * |
609 | mal_rx_bd_offset(mal, i)); | 649 | mal_rx_bd_offset(mal, i)); |
610 | 650 | ||
611 | err = request_irq(mal->serr_irq, mal_serr, 0, "MAL SERR", mal); | 651 | if (mal_has_feature(mal, MAL_FTR_COMMON_ERR_INT)) { |
652 | irqflags = IRQF_SHARED; | ||
653 | hdlr_serr = hdlr_txde = hdlr_rxde = mal_int; | ||
654 | } else { | ||
655 | irqflags = 0; | ||
656 | hdlr_serr = mal_serr; | ||
657 | hdlr_txde = mal_txde; | ||
658 | hdlr_rxde = mal_rxde; | ||
659 | } | ||
660 | |||
661 | err = request_irq(mal->serr_irq, hdlr_serr, irqflags, "MAL SERR", mal); | ||
612 | if (err) | 662 | if (err) |
613 | goto fail2; | 663 | goto fail2; |
614 | err = request_irq(mal->txde_irq, mal_txde, 0, "MAL TX DE", mal); | 664 | err = request_irq(mal->txde_irq, hdlr_txde, irqflags, "MAL TX DE", mal); |
615 | if (err) | 665 | if (err) |
616 | goto fail3; | 666 | goto fail3; |
617 | err = request_irq(mal->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal); | 667 | err = request_irq(mal->txeob_irq, mal_txeob, 0, "MAL TX EOB", mal); |
618 | if (err) | 668 | if (err) |
619 | goto fail4; | 669 | goto fail4; |
620 | err = request_irq(mal->rxde_irq, mal_rxde, 0, "MAL RX DE", mal); | 670 | err = request_irq(mal->rxde_irq, hdlr_rxde, irqflags, "MAL RX DE", mal); |
621 | if (err) | 671 | if (err) |
622 | goto fail5; | 672 | goto fail5; |
623 | err = request_irq(mal->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal); | 673 | err = request_irq(mal->rxeob_irq, mal_rxeob, 0, "MAL RX EOB", mal); |
diff --git a/drivers/net/ibm_newemac/mal.h b/drivers/net/ibm_newemac/mal.h index eaa7262dc079..0b2413839b78 100644 --- a/drivers/net/ibm_newemac/mal.h +++ b/drivers/net/ibm_newemac/mal.h | |||
@@ -213,6 +213,8 @@ struct mal_instance { | |||
213 | struct of_device *ofdev; | 213 | struct of_device *ofdev; |
214 | int index; | 214 | int index; |
215 | spinlock_t lock; | 215 | spinlock_t lock; |
216 | |||
217 | unsigned int features; | ||
216 | }; | 218 | }; |
217 | 219 | ||
218 | static inline u32 get_mal_dcrn(struct mal_instance *mal, int reg) | 220 | static inline u32 get_mal_dcrn(struct mal_instance *mal, int reg) |
@@ -225,6 +227,38 @@ static inline void set_mal_dcrn(struct mal_instance *mal, int reg, u32 val) | |||
225 | dcr_write(mal->dcr_host, reg, val); | 227 | dcr_write(mal->dcr_host, reg, val); |
226 | } | 228 | } |
227 | 229 | ||
230 | /* Features of various MAL implementations */ | ||
231 | |||
232 | /* Set if you have interrupt coalescing and you have to clear the SDR | ||
233 | * register for TXEOB and RXEOB interrupts to work | ||
234 | */ | ||
235 | #define MAL_FTR_CLEAR_ICINTSTAT 0x00000001 | ||
236 | |||
237 | /* Set if your MAL has SERR, TXDE, and RXDE OR'd into a single UIC | ||
238 | * interrupt | ||
239 | */ | ||
240 | #define MAL_FTR_COMMON_ERR_INT 0x00000002 | ||
241 | |||
242 | enum { | ||
243 | MAL_FTRS_ALWAYS = 0, | ||
244 | |||
245 | MAL_FTRS_POSSIBLE = | ||
246 | #ifdef CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT | ||
247 | MAL_FTR_CLEAR_ICINTSTAT | | ||
248 | #endif | ||
249 | #ifdef CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR | ||
250 | MAL_FTR_COMMON_ERR_INT | | ||
251 | #endif | ||
252 | 0, | ||
253 | }; | ||
254 | |||
255 | static inline int mal_has_feature(struct mal_instance *dev, | ||
256 | unsigned long feature) | ||
257 | { | ||
258 | return (MAL_FTRS_ALWAYS & feature) || | ||
259 | (MAL_FTRS_POSSIBLE & dev->features & feature); | ||
260 | } | ||
261 | |||
228 | /* Register MAL devices */ | 262 | /* Register MAL devices */ |
229 | int mal_init(void); | 263 | int mal_init(void); |
230 | void mal_exit(void); | 264 | void mal_exit(void); |
diff --git a/drivers/net/ibm_newemac/phy.c b/drivers/net/ibm_newemac/phy.c index 37bfeea8788a..606db53ef78e 100644 --- a/drivers/net/ibm_newemac/phy.c +++ b/drivers/net/ibm_newemac/phy.c | |||
@@ -38,6 +38,16 @@ static inline void phy_write(struct mii_phy *phy, int reg, int val) | |||
38 | phy->mdio_write(phy->dev, phy->address, reg, val); | 38 | phy->mdio_write(phy->dev, phy->address, reg, val); |
39 | } | 39 | } |
40 | 40 | ||
41 | static inline int gpcs_phy_read(struct mii_phy *phy, int reg) | ||
42 | { | ||
43 | return phy->mdio_read(phy->dev, phy->gpcs_address, reg); | ||
44 | } | ||
45 | |||
46 | static inline void gpcs_phy_write(struct mii_phy *phy, int reg, int val) | ||
47 | { | ||
48 | phy->mdio_write(phy->dev, phy->gpcs_address, reg, val); | ||
49 | } | ||
50 | |||
41 | int emac_mii_reset_phy(struct mii_phy *phy) | 51 | int emac_mii_reset_phy(struct mii_phy *phy) |
42 | { | 52 | { |
43 | int val; | 53 | int val; |
@@ -62,6 +72,37 @@ int emac_mii_reset_phy(struct mii_phy *phy) | |||
62 | return limit <= 0; | 72 | return limit <= 0; |
63 | } | 73 | } |
64 | 74 | ||
75 | int emac_mii_reset_gpcs(struct mii_phy *phy) | ||
76 | { | ||
77 | int val; | ||
78 | int limit = 10000; | ||
79 | |||
80 | val = gpcs_phy_read(phy, MII_BMCR); | ||
81 | val &= ~(BMCR_ISOLATE | BMCR_ANENABLE); | ||
82 | val |= BMCR_RESET; | ||
83 | gpcs_phy_write(phy, MII_BMCR, val); | ||
84 | |||
85 | udelay(300); | ||
86 | |||
87 | while (limit--) { | ||
88 | val = gpcs_phy_read(phy, MII_BMCR); | ||
89 | if (val >= 0 && (val & BMCR_RESET) == 0) | ||
90 | break; | ||
91 | udelay(10); | ||
92 | } | ||
93 | if ((val & BMCR_ISOLATE) && limit > 0) | ||
94 | gpcs_phy_write(phy, MII_BMCR, val & ~BMCR_ISOLATE); | ||
95 | |||
96 | if (limit > 0 && phy->mode == PHY_MODE_SGMII) { | ||
97 | /* Configure GPCS interface to recommended setting for SGMII */ | ||
98 | gpcs_phy_write(phy, 0x04, 0x8120); /* AsymPause, FDX */ | ||
99 | gpcs_phy_write(phy, 0x07, 0x2801); /* msg_pg, toggle */ | ||
100 | gpcs_phy_write(phy, 0x00, 0x0140); /* 1Gbps, FDX */ | ||
101 | } | ||
102 | |||
103 | return limit <= 0; | ||
104 | } | ||
105 | |||
65 | static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) | 106 | static int genmii_setup_aneg(struct mii_phy *phy, u32 advertise) |
66 | { | 107 | { |
67 | int ctl, adv; | 108 | int ctl, adv; |
@@ -332,6 +373,33 @@ static int m88e1111_init(struct mii_phy *phy) | |||
332 | return 0; | 373 | return 0; |
333 | } | 374 | } |
334 | 375 | ||
376 | static int m88e1112_init(struct mii_phy *phy) | ||
377 | { | ||
378 | /* | ||
379 | * Marvell 88E1112 PHY needs to have the SGMII MAC | ||
380 | * interace (page 2) properly configured to | ||
381 | * communicate with the 460EX/GT GPCS interface. | ||
382 | */ | ||
383 | |||
384 | u16 reg_short; | ||
385 | |||
386 | pr_debug("%s: Marvell 88E1112 Ethernet\n", __func__); | ||
387 | |||
388 | /* Set access to Page 2 */ | ||
389 | phy_write(phy, 0x16, 0x0002); | ||
390 | |||
391 | phy_write(phy, 0x00, 0x0040); /* 1Gbps */ | ||
392 | reg_short = (u16)(phy_read(phy, 0x1a)); | ||
393 | reg_short |= 0x8000; /* bypass Auto-Negotiation */ | ||
394 | phy_write(phy, 0x1a, reg_short); | ||
395 | emac_mii_reset_phy(phy); /* reset MAC interface */ | ||
396 | |||
397 | /* Reset access to Page 0 */ | ||
398 | phy_write(phy, 0x16, 0x0000); | ||
399 | |||
400 | return 0; | ||
401 | } | ||
402 | |||
335 | static int et1011c_init(struct mii_phy *phy) | 403 | static int et1011c_init(struct mii_phy *phy) |
336 | { | 404 | { |
337 | u16 reg_short; | 405 | u16 reg_short; |
@@ -384,11 +452,27 @@ static struct mii_phy_def m88e1111_phy_def = { | |||
384 | .ops = &m88e1111_phy_ops, | 452 | .ops = &m88e1111_phy_ops, |
385 | }; | 453 | }; |
386 | 454 | ||
455 | static struct mii_phy_ops m88e1112_phy_ops = { | ||
456 | .init = m88e1112_init, | ||
457 | .setup_aneg = genmii_setup_aneg, | ||
458 | .setup_forced = genmii_setup_forced, | ||
459 | .poll_link = genmii_poll_link, | ||
460 | .read_link = genmii_read_link | ||
461 | }; | ||
462 | |||
463 | static struct mii_phy_def m88e1112_phy_def = { | ||
464 | .phy_id = 0x01410C90, | ||
465 | .phy_id_mask = 0x0ffffff0, | ||
466 | .name = "Marvell 88E1112 Ethernet", | ||
467 | .ops = &m88e1112_phy_ops, | ||
468 | }; | ||
469 | |||
387 | static struct mii_phy_def *mii_phy_table[] = { | 470 | static struct mii_phy_def *mii_phy_table[] = { |
388 | &et1011c_phy_def, | 471 | &et1011c_phy_def, |
389 | &cis8201_phy_def, | 472 | &cis8201_phy_def, |
390 | &bcm5248_phy_def, | 473 | &bcm5248_phy_def, |
391 | &m88e1111_phy_def, | 474 | &m88e1111_phy_def, |
475 | &m88e1112_phy_def, | ||
392 | &genmii_phy_def, | 476 | &genmii_phy_def, |
393 | NULL | 477 | NULL |
394 | }; | 478 | }; |
diff --git a/drivers/net/ibm_newemac/phy.h b/drivers/net/ibm_newemac/phy.h index 1b65c81f6557..5d2bf4cbe50b 100644 --- a/drivers/net/ibm_newemac/phy.h +++ b/drivers/net/ibm_newemac/phy.h | |||
@@ -57,6 +57,7 @@ struct mii_phy { | |||
57 | or determined automaticaly */ | 57 | or determined automaticaly */ |
58 | int address; /* PHY address */ | 58 | int address; /* PHY address */ |
59 | int mode; /* PHY mode */ | 59 | int mode; /* PHY mode */ |
60 | int gpcs_address; /* GPCS PHY address */ | ||
60 | 61 | ||
61 | /* 1: autoneg enabled, 0: disabled */ | 62 | /* 1: autoneg enabled, 0: disabled */ |
62 | int autoneg; | 63 | int autoneg; |
@@ -81,5 +82,6 @@ struct mii_phy { | |||
81 | */ | 82 | */ |
82 | int emac_mii_phy_probe(struct mii_phy *phy, int address); | 83 | int emac_mii_phy_probe(struct mii_phy *phy, int address); |
83 | int emac_mii_reset_phy(struct mii_phy *phy); | 84 | int emac_mii_reset_phy(struct mii_phy *phy); |
85 | int emac_mii_reset_gpcs(struct mii_phy *phy); | ||
84 | 86 | ||
85 | #endif /* __IBM_NEWEMAC_PHY_H */ | 87 | #endif /* __IBM_NEWEMAC_PHY_H */ |