diff options
author | Matt Carlson <mcarlson@broadcom.com> | 2012-12-03 14:36:57 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-12-04 12:58:49 -0500 |
commit | be947307b5b61fabbd76194d02617f9d2653176d (patch) | |
tree | 63f6548d072b3ffd603ce3d7870bf3442ed9572e /drivers/net/ethernet/broadcom/tg3.c | |
parent | 357630668a638418d542d0e331c90c01a091a3f1 (diff) |
tg3: PTP - Add header definitions, initialization and hw access functions.
This patch adds code to write the reference clock. If a chip reset is
performed, the hwclock is reinitialized with the adjusted kernel time
Signed-off-by: Nithin Nayak Sujir <nsujir@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Cc: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/ethernet/broadcom/tg3.c')
-rw-r--r-- | drivers/net/ethernet/broadcom/tg3.c | 61 |
1 files changed, 57 insertions, 4 deletions
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c index a4a5e2d329e4..32ffb5416674 100644 --- a/drivers/net/ethernet/broadcom/tg3.c +++ b/drivers/net/ethernet/broadcom/tg3.c | |||
@@ -54,6 +54,9 @@ | |||
54 | #include <asm/byteorder.h> | 54 | #include <asm/byteorder.h> |
55 | #include <linux/uaccess.h> | 55 | #include <linux/uaccess.h> |
56 | 56 | ||
57 | #include <uapi/linux/net_tstamp.h> | ||
58 | #include <linux/ptp_clock_kernel.h> | ||
59 | |||
57 | #ifdef CONFIG_SPARC | 60 | #ifdef CONFIG_SPARC |
58 | #include <asm/idprom.h> | 61 | #include <asm/idprom.h> |
59 | #include <asm/prom.h> | 62 | #include <asm/prom.h> |
@@ -5516,6 +5519,45 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset) | |||
5516 | return err; | 5519 | return err; |
5517 | } | 5520 | } |
5518 | 5521 | ||
5522 | /* tp->lock must be held */ | ||
5523 | static void tg3_refclk_write(struct tg3 *tp, u64 newval) | ||
5524 | { | ||
5525 | tw32(TG3_EAV_REF_CLCK_CTL, TG3_EAV_REF_CLCK_CTL_STOP); | ||
5526 | tw32(TG3_EAV_REF_CLCK_LSB, newval & 0xffffffff); | ||
5527 | tw32(TG3_EAV_REF_CLCK_MSB, newval >> 32); | ||
5528 | tw32_f(TG3_EAV_REF_CLCK_CTL, TG3_EAV_REF_CLCK_CTL_RESUME); | ||
5529 | } | ||
5530 | |||
5531 | /* tp->lock must be held */ | ||
5532 | static void tg3_ptp_init(struct tg3 *tp) | ||
5533 | { | ||
5534 | if (!tg3_flag(tp, PTP_CAPABLE)) | ||
5535 | return; | ||
5536 | |||
5537 | /* Initialize the hardware clock to the system time. */ | ||
5538 | tg3_refclk_write(tp, ktime_to_ns(ktime_get_real())); | ||
5539 | tp->ptp_adjust = 0; | ||
5540 | } | ||
5541 | |||
5542 | /* tp->lock must be held */ | ||
5543 | static void tg3_ptp_resume(struct tg3 *tp) | ||
5544 | { | ||
5545 | if (!tg3_flag(tp, PTP_CAPABLE)) | ||
5546 | return; | ||
5547 | |||
5548 | tg3_refclk_write(tp, ktime_to_ns(ktime_get_real()) + tp->ptp_adjust); | ||
5549 | tp->ptp_adjust = 0; | ||
5550 | } | ||
5551 | |||
5552 | static void tg3_ptp_fini(struct tg3 *tp) | ||
5553 | { | ||
5554 | if (!tg3_flag(tp, PTP_CAPABLE) || !tp->ptp_clock) | ||
5555 | return; | ||
5556 | |||
5557 | tp->ptp_clock = NULL; | ||
5558 | tp->ptp_adjust = 0; | ||
5559 | } | ||
5560 | |||
5519 | static inline int tg3_irq_sync(struct tg3 *tp) | 5561 | static inline int tg3_irq_sync(struct tg3 *tp) |
5520 | { | 5562 | { |
5521 | return tp->irq_sync; | 5563 | return tp->irq_sync; |
@@ -6528,6 +6570,8 @@ static inline void tg3_netif_stop(struct tg3 *tp) | |||
6528 | /* tp->lock must be held */ | 6570 | /* tp->lock must be held */ |
6529 | static inline void tg3_netif_start(struct tg3 *tp) | 6571 | static inline void tg3_netif_start(struct tg3 *tp) |
6530 | { | 6572 | { |
6573 | tg3_ptp_resume(tp); | ||
6574 | |||
6531 | /* NOTE: unconditional netif_tx_wake_all_queues is only | 6575 | /* NOTE: unconditional netif_tx_wake_all_queues is only |
6532 | * appropriate so long as all callers are assured to | 6576 | * appropriate so long as all callers are assured to |
6533 | * have free tx slots (such as after tg3_init_hw) | 6577 | * have free tx slots (such as after tg3_init_hw) |
@@ -10365,7 +10409,8 @@ static void tg3_ints_fini(struct tg3 *tp) | |||
10365 | tg3_flag_clear(tp, ENABLE_TSS); | 10409 | tg3_flag_clear(tp, ENABLE_TSS); |
10366 | } | 10410 | } |
10367 | 10411 | ||
10368 | static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq) | 10412 | static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq, |
10413 | bool init) | ||
10369 | { | 10414 | { |
10370 | struct net_device *dev = tp->dev; | 10415 | struct net_device *dev = tp->dev; |
10371 | int i, err; | 10416 | int i, err; |
@@ -10444,6 +10489,12 @@ static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq) | |||
10444 | tg3_flag_set(tp, INIT_COMPLETE); | 10489 | tg3_flag_set(tp, INIT_COMPLETE); |
10445 | tg3_enable_ints(tp); | 10490 | tg3_enable_ints(tp); |
10446 | 10491 | ||
10492 | if (init) | ||
10493 | tg3_ptp_init(tp); | ||
10494 | else | ||
10495 | tg3_ptp_resume(tp); | ||
10496 | |||
10497 | |||
10447 | tg3_full_unlock(tp); | 10498 | tg3_full_unlock(tp); |
10448 | 10499 | ||
10449 | netif_tx_start_all_queues(dev); | 10500 | netif_tx_start_all_queues(dev); |
@@ -10541,11 +10592,12 @@ static int tg3_open(struct net_device *dev) | |||
10541 | 10592 | ||
10542 | tg3_full_unlock(tp); | 10593 | tg3_full_unlock(tp); |
10543 | 10594 | ||
10544 | err = tg3_start(tp, true, true); | 10595 | err = tg3_start(tp, true, true, true); |
10545 | if (err) { | 10596 | if (err) { |
10546 | tg3_frob_aux_power(tp, false); | 10597 | tg3_frob_aux_power(tp, false); |
10547 | pci_set_power_state(tp->pdev, PCI_D3hot); | 10598 | pci_set_power_state(tp->pdev, PCI_D3hot); |
10548 | } | 10599 | } |
10600 | |||
10549 | return err; | 10601 | return err; |
10550 | } | 10602 | } |
10551 | 10603 | ||
@@ -10553,6 +10605,8 @@ static int tg3_close(struct net_device *dev) | |||
10553 | { | 10605 | { |
10554 | struct tg3 *tp = netdev_priv(dev); | 10606 | struct tg3 *tp = netdev_priv(dev); |
10555 | 10607 | ||
10608 | tg3_ptp_fini(tp); | ||
10609 | |||
10556 | tg3_stop(tp); | 10610 | tg3_stop(tp); |
10557 | 10611 | ||
10558 | /* Clear stats across close / open calls */ | 10612 | /* Clear stats across close / open calls */ |
@@ -11455,7 +11509,7 @@ static int tg3_set_channels(struct net_device *dev, | |||
11455 | 11509 | ||
11456 | tg3_carrier_off(tp); | 11510 | tg3_carrier_off(tp); |
11457 | 11511 | ||
11458 | tg3_start(tp, true, false); | 11512 | tg3_start(tp, true, false, false); |
11459 | 11513 | ||
11460 | return 0; | 11514 | return 0; |
11461 | } | 11515 | } |
@@ -12508,7 +12562,6 @@ static void tg3_self_test(struct net_device *dev, struct ethtool_test *etest, | |||
12508 | } | 12562 | } |
12509 | 12563 | ||
12510 | tg3_full_lock(tp, irq_sync); | 12564 | tg3_full_lock(tp, irq_sync); |
12511 | |||
12512 | tg3_halt(tp, RESET_KIND_SUSPEND, 1); | 12565 | tg3_halt(tp, RESET_KIND_SUSPEND, 1); |
12513 | err = tg3_nvram_lock(tp); | 12566 | err = tg3_nvram_lock(tp); |
12514 | tg3_halt_cpu(tp, RX_CPU_BASE); | 12567 | tg3_halt_cpu(tp, RX_CPU_BASE); |