diff options
author | Tanli Chang <tanli.chang@sun.com> | 2009-05-26 23:45:50 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-05-26 23:45:50 -0400 |
commit | 9c5cd6708008fcc3dbced6e4b97aa5ecd0634a85 (patch) | |
tree | feb040e38dd505819da5f7264e8c133d4ad643c0 /drivers/net/niu.c | |
parent | 8ca783ab78e3fa518885c4fef93d0972e450a4de (diff) |
niu: Add support for C10NEM
This patch is for supporting C10NEM. C10NEM is a switch module, which
has back-to-back XAUI link connected to blades.
Signed-off-by: Tanli Chang <tanli.chang@sun.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/niu.c')
-rw-r--r-- | drivers/net/niu.c | 57 |
1 files changed, 47 insertions, 10 deletions
diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 2b1745328cf7..0d9de5ac4130 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c | |||
@@ -1317,7 +1317,7 @@ static int bcm8704_reset(struct niu *np) | |||
1317 | 1317 | ||
1318 | err = mdio_read(np, np->phy_addr, | 1318 | err = mdio_read(np, np->phy_addr, |
1319 | BCM8704_PHYXS_DEV_ADDR, MII_BMCR); | 1319 | BCM8704_PHYXS_DEV_ADDR, MII_BMCR); |
1320 | if (err < 0) | 1320 | if (err < 0 || err == 0xffff) |
1321 | return err; | 1321 | return err; |
1322 | err |= BMCR_RESET; | 1322 | err |= BMCR_RESET; |
1323 | err = mdio_write(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR, | 1323 | err = mdio_write(np, np->phy_addr, BCM8704_PHYXS_DEV_ADDR, |
@@ -2042,7 +2042,7 @@ static int link_status_10g_bcm8706(struct niu *np, int *link_up_p) | |||
2042 | 2042 | ||
2043 | err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR, | 2043 | err = mdio_read(np, np->phy_addr, BCM8704_PMA_PMD_DEV_ADDR, |
2044 | BCM8704_PMD_RCV_SIGDET); | 2044 | BCM8704_PMD_RCV_SIGDET); |
2045 | if (err < 0) | 2045 | if (err < 0 || err == 0xffff) |
2046 | goto out; | 2046 | goto out; |
2047 | if (!(err & PMD_RCV_SIGDET_GLOBAL)) { | 2047 | if (!(err & PMD_RCV_SIGDET_GLOBAL)) { |
2048 | err = 0; | 2048 | err = 0; |
@@ -2083,8 +2083,6 @@ static int link_status_10g_bcm8706(struct niu *np, int *link_up_p) | |||
2083 | 2083 | ||
2084 | out: | 2084 | out: |
2085 | *link_up_p = link_up; | 2085 | *link_up_p = link_up; |
2086 | if (np->flags & NIU_FLAGS_HOTPLUG_PHY) | ||
2087 | err = 0; | ||
2088 | return err; | 2086 | return err; |
2089 | } | 2087 | } |
2090 | 2088 | ||
@@ -2220,10 +2218,17 @@ static int link_status_10g_hotplug(struct niu *np, int *link_up_p) | |||
2220 | if (phy_present != phy_present_prev) { | 2218 | if (phy_present != phy_present_prev) { |
2221 | /* state change */ | 2219 | /* state change */ |
2222 | if (phy_present) { | 2220 | if (phy_present) { |
2221 | /* A NEM was just plugged in */ | ||
2223 | np->flags |= NIU_FLAGS_HOTPLUG_PHY_PRESENT; | 2222 | np->flags |= NIU_FLAGS_HOTPLUG_PHY_PRESENT; |
2224 | if (np->phy_ops->xcvr_init) | 2223 | if (np->phy_ops->xcvr_init) |
2225 | err = np->phy_ops->xcvr_init(np); | 2224 | err = np->phy_ops->xcvr_init(np); |
2226 | if (err) { | 2225 | if (err) { |
2226 | err = mdio_read(np, np->phy_addr, | ||
2227 | BCM8704_PHYXS_DEV_ADDR, MII_BMCR); | ||
2228 | if (err == 0xffff) { | ||
2229 | /* No mdio, back-to-back XAUI */ | ||
2230 | goto out; | ||
2231 | } | ||
2227 | /* debounce */ | 2232 | /* debounce */ |
2228 | np->flags &= ~NIU_FLAGS_HOTPLUG_PHY_PRESENT; | 2233 | np->flags &= ~NIU_FLAGS_HOTPLUG_PHY_PRESENT; |
2229 | } | 2234 | } |
@@ -2234,13 +2239,21 @@ static int link_status_10g_hotplug(struct niu *np, int *link_up_p) | |||
2234 | np->dev->name); | 2239 | np->dev->name); |
2235 | } | 2240 | } |
2236 | } | 2241 | } |
2237 | if (np->flags & NIU_FLAGS_HOTPLUG_PHY_PRESENT) | 2242 | out: |
2243 | if (np->flags & NIU_FLAGS_HOTPLUG_PHY_PRESENT) { | ||
2238 | err = link_status_10g_bcm8706(np, link_up_p); | 2244 | err = link_status_10g_bcm8706(np, link_up_p); |
2245 | if (err == 0xffff) { | ||
2246 | /* No mdio, back-to-back XAUI: it is C10NEM */ | ||
2247 | *link_up_p = 1; | ||
2248 | np->link_config.active_speed = SPEED_10000; | ||
2249 | np->link_config.active_duplex = DUPLEX_FULL; | ||
2250 | } | ||
2251 | } | ||
2239 | } | 2252 | } |
2240 | 2253 | ||
2241 | spin_unlock_irqrestore(&np->lock, flags); | 2254 | spin_unlock_irqrestore(&np->lock, flags); |
2242 | 2255 | ||
2243 | return err; | 2256 | return 0; |
2244 | } | 2257 | } |
2245 | 2258 | ||
2246 | static int niu_link_status(struct niu *np, int *link_up_p) | 2259 | static int niu_link_status(struct niu *np, int *link_up_p) |
@@ -2312,6 +2325,12 @@ static const struct niu_phy_ops phy_ops_10g_fiber_hotplug = { | |||
2312 | .link_status = link_status_10g_hotplug, | 2325 | .link_status = link_status_10g_hotplug, |
2313 | }; | 2326 | }; |
2314 | 2327 | ||
2328 | static const struct niu_phy_ops phy_ops_niu_10g_hotplug = { | ||
2329 | .serdes_init = serdes_init_niu_10g_fiber, | ||
2330 | .xcvr_init = xcvr_init_10g_bcm8706, | ||
2331 | .link_status = link_status_10g_hotplug, | ||
2332 | }; | ||
2333 | |||
2315 | static const struct niu_phy_ops phy_ops_10g_copper = { | 2334 | static const struct niu_phy_ops phy_ops_10g_copper = { |
2316 | .serdes_init = serdes_init_10g, | 2335 | .serdes_init = serdes_init_10g, |
2317 | .link_status = link_status_10g, /* XXX */ | 2336 | .link_status = link_status_10g, /* XXX */ |
@@ -2358,6 +2377,11 @@ static const struct niu_phy_template phy_template_10g_fiber_hotplug = { | |||
2358 | .phy_addr_base = 8, | 2377 | .phy_addr_base = 8, |
2359 | }; | 2378 | }; |
2360 | 2379 | ||
2380 | static const struct niu_phy_template phy_template_niu_10g_hotplug = { | ||
2381 | .ops = &phy_ops_niu_10g_hotplug, | ||
2382 | .phy_addr_base = 8, | ||
2383 | }; | ||
2384 | |||
2361 | static const struct niu_phy_template phy_template_10g_copper = { | 2385 | static const struct niu_phy_template phy_template_10g_copper = { |
2362 | .ops = &phy_ops_10g_copper, | 2386 | .ops = &phy_ops_10g_copper, |
2363 | .phy_addr_base = 10, | 2387 | .phy_addr_base = 10, |
@@ -2542,8 +2566,16 @@ static int niu_determine_phy_disposition(struct niu *np) | |||
2542 | case NIU_FLAGS_10G | NIU_FLAGS_FIBER: | 2566 | case NIU_FLAGS_10G | NIU_FLAGS_FIBER: |
2543 | /* 10G Fiber */ | 2567 | /* 10G Fiber */ |
2544 | default: | 2568 | default: |
2545 | tp = &phy_template_niu_10g_fiber; | 2569 | if (np->flags & NIU_FLAGS_HOTPLUG_PHY) { |
2546 | phy_addr_off += np->port; | 2570 | tp = &phy_template_niu_10g_hotplug; |
2571 | if (np->port == 0) | ||
2572 | phy_addr_off = 8; | ||
2573 | if (np->port == 1) | ||
2574 | phy_addr_off = 12; | ||
2575 | } else { | ||
2576 | tp = &phy_template_niu_10g_fiber; | ||
2577 | phy_addr_off += np->port; | ||
2578 | } | ||
2547 | break; | 2579 | break; |
2548 | } | 2580 | } |
2549 | } else { | 2581 | } else { |
@@ -2630,11 +2662,11 @@ static int niu_init_link(struct niu *np) | |||
2630 | msleep(200); | 2662 | msleep(200); |
2631 | } | 2663 | } |
2632 | err = niu_serdes_init(np); | 2664 | err = niu_serdes_init(np); |
2633 | if (err) | 2665 | if (err && !(np->flags & NIU_FLAGS_HOTPLUG_PHY)) |
2634 | return err; | 2666 | return err; |
2635 | msleep(200); | 2667 | msleep(200); |
2636 | err = niu_xcvr_init(np); | 2668 | err = niu_xcvr_init(np); |
2637 | if (!err) | 2669 | if (!err || (np->flags & NIU_FLAGS_HOTPLUG_PHY)) |
2638 | niu_link_status(np, &ignore); | 2670 | niu_link_status(np, &ignore); |
2639 | return 0; | 2671 | return 0; |
2640 | } | 2672 | } |
@@ -9346,6 +9378,11 @@ static int __devinit niu_get_of_props(struct niu *np) | |||
9346 | if (model) | 9378 | if (model) |
9347 | strcpy(np->vpd.model, model); | 9379 | strcpy(np->vpd.model, model); |
9348 | 9380 | ||
9381 | if (of_find_property(dp, "hot-swappable-phy", &prop_len)) { | ||
9382 | np->flags |= (NIU_FLAGS_10G | NIU_FLAGS_FIBER | | ||
9383 | NIU_FLAGS_HOTPLUG_PHY); | ||
9384 | } | ||
9385 | |||
9349 | return 0; | 9386 | return 0; |
9350 | #else | 9387 | #else |
9351 | return -EINVAL; | 9388 | return -EINVAL; |