Skip to content

Commit cc75549

Browse files
HoratiuVulturdavem330
authored andcommitted
net: micrel: Change to receive timestamp in the frame for lan8841
Currently for each timestamp frame, the SW needs to go and read the received timestamp over the MDIO bus. But the HW has the capability to store the received nanoseconds part and the least significant two bits of the seconds in the reserved field of the PTP header. In this way we could save few MDIO transactions (actually a little more transactions because the access to the PTP registers are indirect) for each received frame. Instead of reading the rest of seconds part of the timestamp of the frame using MDIO transactions schedule PTP worker thread to read the seconds part every 500ms and then for each of the received frames use this information. Because if for example running with 512 frames per second, there is no point to read 512 times the second part. Doing all these changes will give a great CPU usage performance. Running ptp4l with logSyncInterval of -9 will give a ~60% CPU improvement. Signed-off-by: Horatiu Vultur <[email protected]> Acked-by: Richard Cochran <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 4cb13ff commit cc75549

File tree

1 file changed

+154
-96
lines changed

1 file changed

+154
-96
lines changed

drivers/net/phy/micrel.c

Lines changed: 154 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,9 @@
252252
#define PS_TO_REG 200
253253
#define FIFO_SIZE 8
254254

255+
/* Delay used to get the second part from the LTC */
256+
#define LAN8841_GET_SEC_LTC_DELAY (500 * NSEC_PER_MSEC)
257+
255258
struct kszphy_hw_stat {
256259
const char *string;
257260
u8 reg;
@@ -319,6 +322,10 @@ struct kszphy_ptp_priv {
319322
/* Lock for ptp_clock */
320323
struct mutex ptp_lock;
321324
struct ptp_pin_desc *pin_config;
325+
326+
s64 seconds;
327+
/* Lock for accessing seconds */
328+
spinlock_t seconds_lock;
322329
};
323330

324331
struct kszphy_priv {
@@ -3311,6 +3318,9 @@ static int lan8814_probe(struct phy_device *phydev)
33113318
#define LAN8841_PTP_CMD_CTL_PTP_RESET BIT(0)
33123319
#define LAN8841_PTP_RX_PARSE_CONFIG 368
33133320
#define LAN8841_PTP_TX_PARSE_CONFIG 432
3321+
#define LAN8841_PTP_RX_MODE 381
3322+
#define LAN8841_PTP_INSERT_TS_EN BIT(0)
3323+
#define LAN8841_PTP_INSERT_TS_32BIT BIT(1)
33143324

33153325
static int lan8841_config_init(struct phy_device *phydev)
33163326
{
@@ -3459,68 +3469,18 @@ static void lan8841_ptp_process_tx_ts(struct kszphy_ptp_priv *ptp_priv)
34593469
lan8814_match_tx_skb(ptp_priv, sec, nsec, seq);
34603470
}
34613471

3462-
#define LAN8841_PTP_RX_INGRESS_SEC_LO 389
3463-
#define LAN8841_PTP_RX_INGRESS_SEC_HI 388
3464-
#define LAN8841_PTP_RX_INGRESS_NS_LO 387
3465-
#define LAN8841_PTP_RX_INGRESS_NS_HI 386
3466-
#define LAN8841_PTP_RX_INGRESS_NSEC_HI_VALID BIT(15)
3467-
#define LAN8841_PTP_RX_MSG_HEADER2 391
3468-
3469-
static struct lan8814_ptp_rx_ts *lan8841_ptp_get_rx_ts(struct kszphy_ptp_priv *ptp_priv)
3470-
{
3471-
struct phy_device *phydev = ptp_priv->phydev;
3472-
struct lan8814_ptp_rx_ts *rx_ts;
3473-
u32 sec, nsec;
3474-
u16 seq;
3475-
3476-
nsec = phy_read_mmd(phydev, 2, LAN8841_PTP_RX_INGRESS_NS_HI);
3477-
if (!(nsec & LAN8841_PTP_RX_INGRESS_NSEC_HI_VALID))
3478-
return NULL;
3479-
3480-
nsec = ((nsec & 0x3fff) << 16);
3481-
nsec = nsec | phy_read_mmd(phydev, 2, LAN8841_PTP_RX_INGRESS_NS_LO);
3482-
3483-
sec = phy_read_mmd(phydev, 2, LAN8841_PTP_RX_INGRESS_SEC_HI);
3484-
sec = sec << 16;
3485-
sec = sec | phy_read_mmd(phydev, 2, LAN8841_PTP_RX_INGRESS_SEC_LO);
3486-
3487-
seq = phy_read_mmd(phydev, 2, LAN8841_PTP_RX_MSG_HEADER2);
3488-
3489-
rx_ts = kzalloc(sizeof(*rx_ts), GFP_KERNEL);
3490-
if (!rx_ts)
3491-
return NULL;
3492-
3493-
rx_ts->seconds = sec;
3494-
rx_ts->nsec = nsec;
3495-
rx_ts->seq_id = seq;
3496-
3497-
return rx_ts;
3498-
}
3499-
3500-
static void lan8841_ptp_process_rx_ts(struct kszphy_ptp_priv *ptp_priv)
3501-
{
3502-
struct lan8814_ptp_rx_ts *rx_ts;
3503-
3504-
while ((rx_ts = lan8841_ptp_get_rx_ts(ptp_priv)) != NULL)
3505-
lan8814_match_rx_ts(ptp_priv, rx_ts);
3506-
}
3507-
35083472
#define LAN8841_PTP_INT_STS 259
35093473
#define LAN8841_PTP_INT_STS_PTP_TX_TS_OVRFL_INT BIT(13)
35103474
#define LAN8841_PTP_INT_STS_PTP_TX_TS_INT BIT(12)
3511-
#define LAN8841_PTP_INT_STS_PTP_RX_TS_OVRFL_INT BIT(9)
3512-
#define LAN8841_PTP_INT_STS_PTP_RX_TS_INT BIT(8)
35133475
#define LAN8841_PTP_INT_STS_PTP_GPIO_CAP_INT BIT(2)
35143476

3515-
static void lan8841_ptp_flush_fifo(struct kszphy_ptp_priv *ptp_priv, bool egress)
3477+
static void lan8841_ptp_flush_fifo(struct kszphy_ptp_priv *ptp_priv)
35163478
{
35173479
struct phy_device *phydev = ptp_priv->phydev;
35183480
int i;
35193481

35203482
for (i = 0; i < FIFO_SIZE; ++i)
3521-
phy_read_mmd(phydev, 2,
3522-
egress ? LAN8841_PTP_TX_MSG_HEADER2 :
3523-
LAN8841_PTP_RX_MSG_HEADER2);
3483+
phy_read_mmd(phydev, 2, LAN8841_PTP_TX_MSG_HEADER2);
35243484

35253485
phy_read_mmd(phydev, 2, LAN8841_PTP_INT_STS);
35263486
}
@@ -3598,23 +3558,17 @@ static void lan8841_handle_ptp_interrupt(struct phy_device *phydev)
35983558
if (status & LAN8841_PTP_INT_STS_PTP_TX_TS_INT)
35993559
lan8841_ptp_process_tx_ts(ptp_priv);
36003560

3601-
if (status & LAN8841_PTP_INT_STS_PTP_RX_TS_INT)
3602-
lan8841_ptp_process_rx_ts(ptp_priv);
3603-
36043561
if (status & LAN8841_PTP_INT_STS_PTP_GPIO_CAP_INT)
36053562
lan8841_gpio_process_cap(ptp_priv);
36063563

36073564
if (status & LAN8841_PTP_INT_STS_PTP_TX_TS_OVRFL_INT) {
3608-
lan8841_ptp_flush_fifo(ptp_priv, true);
3565+
lan8841_ptp_flush_fifo(ptp_priv);
36093566
skb_queue_purge(&ptp_priv->tx_queue);
36103567
}
36113568

3612-
if (status & LAN8841_PTP_INT_STS_PTP_RX_TS_OVRFL_INT) {
3613-
lan8841_ptp_flush_fifo(ptp_priv, false);
3614-
skb_queue_purge(&ptp_priv->rx_queue);
3615-
}
3616-
3617-
} while (status);
3569+
} while (status & (LAN8841_PTP_INT_STS_PTP_TX_TS_INT |
3570+
LAN8841_PTP_INT_STS_PTP_GPIO_CAP_INT |
3571+
LAN8841_PTP_INT_STS_PTP_TX_TS_OVRFL_INT));
36183572
}
36193573

36203574
#define LAN8841_INTS_PTP BIT(9)
@@ -3678,32 +3632,46 @@ static int lan8841_ts_info(struct mii_timestamper *mii_ts,
36783632
#define LAN8841_PTP_INT_EN 260
36793633
#define LAN8841_PTP_INT_EN_PTP_TX_TS_OVRFL_EN BIT(13)
36803634
#define LAN8841_PTP_INT_EN_PTP_TX_TS_EN BIT(12)
3681-
#define LAN8841_PTP_INT_EN_PTP_RX_TS_OVRFL_EN BIT(9)
3682-
#define LAN8841_PTP_INT_EN_PTP_RX_TS_EN BIT(8)
36833635

3684-
static void lan8841_ptp_enable_int(struct kszphy_ptp_priv *ptp_priv,
3685-
bool enable)
3636+
static void lan8841_ptp_enable_processing(struct kszphy_ptp_priv *ptp_priv,
3637+
bool enable)
36863638
{
36873639
struct phy_device *phydev = ptp_priv->phydev;
36883640

3689-
if (enable)
3690-
/* Enable interrupts */
3641+
if (enable) {
3642+
/* Enable interrupts on the TX side */
36913643
phy_modify_mmd(phydev, 2, LAN8841_PTP_INT_EN,
36923644
LAN8841_PTP_INT_EN_PTP_TX_TS_OVRFL_EN |
3693-
LAN8841_PTP_INT_EN_PTP_RX_TS_OVRFL_EN |
3694-
LAN8841_PTP_INT_EN_PTP_TX_TS_EN |
3695-
LAN8841_PTP_INT_EN_PTP_RX_TS_EN,
3645+
LAN8841_PTP_INT_EN_PTP_TX_TS_EN,
36963646
LAN8841_PTP_INT_EN_PTP_TX_TS_OVRFL_EN |
3697-
LAN8841_PTP_INT_EN_PTP_RX_TS_OVRFL_EN |
3698-
LAN8841_PTP_INT_EN_PTP_TX_TS_EN |
3699-
LAN8841_PTP_INT_EN_PTP_RX_TS_EN);
3700-
else
3701-
/* Disable interrupts */
3647+
LAN8841_PTP_INT_EN_PTP_TX_TS_EN);
3648+
3649+
/* Enable the modification of the frame on RX side,
3650+
* this will add the ns and 2 bits of sec in the reserved field
3651+
* of the PTP header
3652+
*/
3653+
phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
3654+
LAN8841_PTP_RX_MODE,
3655+
LAN8841_PTP_INSERT_TS_EN |
3656+
LAN8841_PTP_INSERT_TS_32BIT,
3657+
LAN8841_PTP_INSERT_TS_EN |
3658+
LAN8841_PTP_INSERT_TS_32BIT);
3659+
3660+
ptp_schedule_worker(ptp_priv->ptp_clock, 0);
3661+
} else {
3662+
/* Disable interrupts on the TX side */
37023663
phy_modify_mmd(phydev, 2, LAN8841_PTP_INT_EN,
37033664
LAN8841_PTP_INT_EN_PTP_TX_TS_OVRFL_EN |
3704-
LAN8841_PTP_INT_EN_PTP_RX_TS_OVRFL_EN |
3705-
LAN8841_PTP_INT_EN_PTP_TX_TS_EN |
3706-
LAN8841_PTP_INT_EN_PTP_RX_TS_EN, 0);
3665+
LAN8841_PTP_INT_EN_PTP_TX_TS_EN, 0);
3666+
3667+
/* Disable modification of the RX frames */
3668+
phy_modify_mmd(phydev, KSZ9131RN_MMD_COMMON_CTRL_REG,
3669+
LAN8841_PTP_RX_MODE,
3670+
LAN8841_PTP_INSERT_TS_EN |
3671+
LAN8841_PTP_INSERT_TS_32BIT, 0);
3672+
3673+
ptp_cancel_worker_sync(ptp_priv->ptp_clock);
3674+
}
37073675
}
37083676

37093677
#define LAN8841_PTP_RX_TIMESTAMP_EN 379
@@ -3714,7 +3682,6 @@ static int lan8841_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr)
37143682
{
37153683
struct kszphy_ptp_priv *ptp_priv = container_of(mii_ts, struct kszphy_ptp_priv, mii_ts);
37163684
struct phy_device *phydev = ptp_priv->phydev;
3717-
struct lan8814_ptp_rx_ts *rx_ts, *tmp;
37183685
struct hwtstamp_config config;
37193686
int txcfg = 0, rxcfg = 0;
37203687
int pkt_ts_enable;
@@ -3778,24 +3745,61 @@ static int lan8841_hwtstamp(struct mii_timestamper *mii_ts, struct ifreq *ifr)
37783745
PTP_TX_MOD_TX_PTP_SYNC_TS_INSERT_ : 0);
37793746

37803747
/* Now enable/disable the timestamping */
3781-
lan8841_ptp_enable_int(ptp_priv,
3782-
config.rx_filter != HWTSTAMP_FILTER_NONE);
3783-
3784-
/* In case of multiple starts and stops, these needs to be cleared */
3785-
list_for_each_entry_safe(rx_ts, tmp, &ptp_priv->rx_ts_list, list) {
3786-
list_del(&rx_ts->list);
3787-
kfree(rx_ts);
3788-
}
3748+
lan8841_ptp_enable_processing(ptp_priv,
3749+
config.rx_filter != HWTSTAMP_FILTER_NONE);
37893750

3790-
skb_queue_purge(&ptp_priv->rx_queue);
37913751
skb_queue_purge(&ptp_priv->tx_queue);
37923752

3793-
lan8841_ptp_flush_fifo(ptp_priv, false);
3794-
lan8841_ptp_flush_fifo(ptp_priv, true);
3753+
lan8841_ptp_flush_fifo(ptp_priv);
37953754

37963755
return copy_to_user(ifr->ifr_data, &config, sizeof(config)) ? -EFAULT : 0;
37973756
}
37983757

3758+
static bool lan8841_rxtstamp(struct mii_timestamper *mii_ts,
3759+
struct sk_buff *skb, int type)
3760+
{
3761+
struct kszphy_ptp_priv *ptp_priv =
3762+
container_of(mii_ts, struct kszphy_ptp_priv, mii_ts);
3763+
struct ptp_header *header = ptp_parse_header(skb, type);
3764+
struct skb_shared_hwtstamps *shhwtstamps;
3765+
struct timespec64 ts;
3766+
unsigned long flags;
3767+
u32 ts_header;
3768+
3769+
if (!header)
3770+
return false;
3771+
3772+
if (ptp_priv->rx_filter == HWTSTAMP_FILTER_NONE ||
3773+
type == PTP_CLASS_NONE)
3774+
return false;
3775+
3776+
if ((type & ptp_priv->version) == 0 || (type & ptp_priv->layer) == 0)
3777+
return false;
3778+
3779+
spin_lock_irqsave(&ptp_priv->seconds_lock, flags);
3780+
ts.tv_sec = ptp_priv->seconds;
3781+
spin_unlock_irqrestore(&ptp_priv->seconds_lock, flags);
3782+
ts_header = __be32_to_cpu(header->reserved2);
3783+
3784+
shhwtstamps = skb_hwtstamps(skb);
3785+
memset(shhwtstamps, 0, sizeof(*shhwtstamps));
3786+
3787+
/* Check for any wrap arounds for the second part */
3788+
if ((ts.tv_sec & GENMASK(1, 0)) == 0 && (ts_header >> 30) == 3)
3789+
ts.tv_sec -= GENMASK(1, 0) + 1;
3790+
else if ((ts.tv_sec & GENMASK(1, 0)) == 3 && (ts_header >> 30) == 0)
3791+
ts.tv_sec += 1;
3792+
3793+
shhwtstamps->hwtstamp =
3794+
ktime_set((ts.tv_sec & ~(GENMASK(1, 0))) | ts_header >> 30,
3795+
ts_header & GENMASK(29, 0));
3796+
header->reserved2 = 0;
3797+
3798+
netif_rx(skb);
3799+
3800+
return true;
3801+
}
3802+
37993803
#define LAN8841_EVENT_A 0
38003804
#define LAN8841_EVENT_B 1
38013805
#define LAN8841_PTP_LTC_TARGET_SEC_HI(event) ((event) == LAN8841_EVENT_A ? 278 : 288)
@@ -3880,6 +3884,7 @@ static int lan8841_ptp_settime64(struct ptp_clock_info *ptp,
38803884
struct kszphy_ptp_priv *ptp_priv = container_of(ptp, struct kszphy_ptp_priv,
38813885
ptp_clock_info);
38823886
struct phy_device *phydev = ptp_priv->phydev;
3887+
unsigned long flags;
38833888
int ret;
38843889

38853890
/* Set the value to be stored */
@@ -3896,6 +3901,10 @@ static int lan8841_ptp_settime64(struct ptp_clock_info *ptp,
38963901
ret = lan8841_ptp_update_target(ptp_priv, ts);
38973902
mutex_unlock(&ptp_priv->ptp_lock);
38983903

3904+
spin_lock_irqsave(&ptp_priv->seconds_lock, flags);
3905+
ptp_priv->seconds = ts->tv_sec;
3906+
spin_unlock_irqrestore(&ptp_priv->seconds_lock, flags);
3907+
38993908
return ret;
39003909
}
39013910

@@ -3936,6 +3945,30 @@ static int lan8841_ptp_gettime64(struct ptp_clock_info *ptp,
39363945
return 0;
39373946
}
39383947

3948+
static void lan8841_ptp_getseconds(struct ptp_clock_info *ptp,
3949+
struct timespec64 *ts)
3950+
{
3951+
struct kszphy_ptp_priv *ptp_priv = container_of(ptp, struct kszphy_ptp_priv,
3952+
ptp_clock_info);
3953+
struct phy_device *phydev = ptp_priv->phydev;
3954+
time64_t s;
3955+
3956+
mutex_lock(&ptp_priv->ptp_lock);
3957+
/* Issue the command to read the LTC */
3958+
phy_write_mmd(phydev, 2, LAN8841_PTP_CMD_CTL,
3959+
LAN8841_PTP_CMD_CTL_PTP_LTC_READ);
3960+
3961+
/* Read the LTC */
3962+
s = phy_read_mmd(phydev, 2, LAN8841_PTP_LTC_RD_SEC_HI);
3963+
s <<= 16;
3964+
s |= phy_read_mmd(phydev, 2, LAN8841_PTP_LTC_RD_SEC_MID);
3965+
s <<= 16;
3966+
s |= phy_read_mmd(phydev, 2, LAN8841_PTP_LTC_RD_SEC_LO);
3967+
mutex_unlock(&ptp_priv->ptp_lock);
3968+
3969+
set_normalized_timespec64(ts, s, 0);
3970+
}
3971+
39393972
#define LAN8841_PTP_LTC_STEP_ADJ_LO 276
39403973
#define LAN8841_PTP_LTC_STEP_ADJ_HI 275
39413974
#define LAN8841_PTP_LTC_STEP_ADJ_DIR BIT(15)
@@ -4438,6 +4471,22 @@ static int lan8841_ptp_enable(struct ptp_clock_info *ptp,
44384471
return 0;
44394472
}
44404473

4474+
static long lan8841_ptp_do_aux_work(struct ptp_clock_info *ptp)
4475+
{
4476+
struct kszphy_ptp_priv *ptp_priv = container_of(ptp, struct kszphy_ptp_priv,
4477+
ptp_clock_info);
4478+
struct timespec64 ts;
4479+
unsigned long flags;
4480+
4481+
lan8841_ptp_getseconds(&ptp_priv->ptp_clock_info, &ts);
4482+
4483+
spin_lock_irqsave(&ptp_priv->seconds_lock, flags);
4484+
ptp_priv->seconds = ts.tv_sec;
4485+
spin_unlock_irqrestore(&ptp_priv->seconds_lock, flags);
4486+
4487+
return nsecs_to_jiffies(LAN8841_GET_SEC_LTC_DELAY);
4488+
}
4489+
44414490
static struct ptp_clock_info lan8841_ptp_clock_info = {
44424491
.owner = THIS_MODULE,
44434492
.name = "lan8841 ptp",
@@ -4448,6 +4497,7 @@ static struct ptp_clock_info lan8841_ptp_clock_info = {
44484497
.adjfine = lan8841_ptp_adjfine,
44494498
.verify = lan8841_ptp_verify,
44504499
.enable = lan8841_ptp_enable,
4500+
.do_aux_work = lan8841_ptp_do_aux_work,
44514501
.n_per_out = LAN8841_PTP_GPIO_NUM,
44524502
.n_ext_ts = LAN8841_PTP_GPIO_NUM,
44534503
.n_pins = LAN8841_PTP_GPIO_NUM,
@@ -4508,13 +4558,11 @@ static int lan8841_probe(struct phy_device *phydev)
45084558

45094559
/* Initialize the SW */
45104560
skb_queue_head_init(&ptp_priv->tx_queue);
4511-
skb_queue_head_init(&ptp_priv->rx_queue);
4512-
INIT_LIST_HEAD(&ptp_priv->rx_ts_list);
4513-
spin_lock_init(&ptp_priv->rx_ts_lock);
45144561
ptp_priv->phydev = phydev;
45154562
mutex_init(&ptp_priv->ptp_lock);
4563+
spin_lock_init(&ptp_priv->seconds_lock);
45164564

4517-
ptp_priv->mii_ts.rxtstamp = lan8814_rxtstamp;
4565+
ptp_priv->mii_ts.rxtstamp = lan8841_rxtstamp;
45184566
ptp_priv->mii_ts.txtstamp = lan8814_txtstamp;
45194567
ptp_priv->mii_ts.hwtstamp = lan8841_hwtstamp;
45204568
ptp_priv->mii_ts.ts_info = lan8841_ts_info;
@@ -4524,6 +4572,16 @@ static int lan8841_probe(struct phy_device *phydev)
45244572
return 0;
45254573
}
45264574

4575+
static int lan8841_suspend(struct phy_device *phydev)
4576+
{
4577+
struct kszphy_priv *priv = phydev->priv;
4578+
struct kszphy_ptp_priv *ptp_priv = &priv->ptp_priv;
4579+
4580+
ptp_cancel_worker_sync(ptp_priv->ptp_clock);
4581+
4582+
return genphy_suspend(phydev);
4583+
}
4584+
45274585
static struct phy_driver ksphy_driver[] = {
45284586
{
45294587
.phy_id = PHY_ID_KS8737,
@@ -4747,7 +4805,7 @@ static struct phy_driver ksphy_driver[] = {
47474805
.get_sset_count = kszphy_get_sset_count,
47484806
.get_strings = kszphy_get_strings,
47494807
.get_stats = kszphy_get_stats,
4750-
.suspend = genphy_suspend,
4808+
.suspend = lan8841_suspend,
47514809
.resume = genphy_resume,
47524810
.cable_test_start = lan8814_cable_test_start,
47534811
.cable_test_get_status = ksz886x_cable_test_get_status,

0 commit comments

Comments
 (0)