Commit 99f5711e authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

mlx4: do not use rwlock in fast path

Using a reader-writer lock in fast path is silly, when we can
instead use RCU or a seqlock.

For mlx4 hwstamp clock, a seqlock is the way to go, removing
two atomic operations and false sharing.
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Cc: Tariq Toukan <tariqt@mellanox.com>
Reviewed-by: default avatarTariq Toukan <tariqt@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent d5bc1613
...@@ -62,12 +62,13 @@ void mlx4_en_fill_hwtstamps(struct mlx4_en_dev *mdev, ...@@ -62,12 +62,13 @@ void mlx4_en_fill_hwtstamps(struct mlx4_en_dev *mdev,
struct skb_shared_hwtstamps *hwts, struct skb_shared_hwtstamps *hwts,
u64 timestamp) u64 timestamp)
{ {
unsigned long flags; unsigned int seq;
u64 nsec; u64 nsec;
read_lock_irqsave(&mdev->clock_lock, flags); do {
nsec = timecounter_cyc2time(&mdev->clock, timestamp); seq = read_seqbegin(&mdev->clock_lock);
read_unlock_irqrestore(&mdev->clock_lock, flags); nsec = timecounter_cyc2time(&mdev->clock, timestamp);
} while (read_seqretry(&mdev->clock_lock, seq));
memset(hwts, 0, sizeof(struct skb_shared_hwtstamps)); memset(hwts, 0, sizeof(struct skb_shared_hwtstamps));
hwts->hwtstamp = ns_to_ktime(nsec); hwts->hwtstamp = ns_to_ktime(nsec);
...@@ -95,9 +96,9 @@ void mlx4_en_ptp_overflow_check(struct mlx4_en_dev *mdev) ...@@ -95,9 +96,9 @@ void mlx4_en_ptp_overflow_check(struct mlx4_en_dev *mdev)
unsigned long flags; unsigned long flags;
if (timeout) { if (timeout) {
write_lock_irqsave(&mdev->clock_lock, flags); write_seqlock_irqsave(&mdev->clock_lock, flags);
timecounter_read(&mdev->clock); timecounter_read(&mdev->clock);
write_unlock_irqrestore(&mdev->clock_lock, flags); write_sequnlock_irqrestore(&mdev->clock_lock, flags);
mdev->last_overflow_check = jiffies; mdev->last_overflow_check = jiffies;
} }
} }
...@@ -128,10 +129,10 @@ static int mlx4_en_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta) ...@@ -128,10 +129,10 @@ static int mlx4_en_phc_adjfreq(struct ptp_clock_info *ptp, s32 delta)
adj *= delta; adj *= delta;
diff = div_u64(adj, 1000000000ULL); diff = div_u64(adj, 1000000000ULL);
write_lock_irqsave(&mdev->clock_lock, flags); write_seqlock_irqsave(&mdev->clock_lock, flags);
timecounter_read(&mdev->clock); timecounter_read(&mdev->clock);
mdev->cycles.mult = neg_adj ? mult - diff : mult + diff; mdev->cycles.mult = neg_adj ? mult - diff : mult + diff;
write_unlock_irqrestore(&mdev->clock_lock, flags); write_sequnlock_irqrestore(&mdev->clock_lock, flags);
return 0; return 0;
} }
...@@ -149,9 +150,9 @@ static int mlx4_en_phc_adjtime(struct ptp_clock_info *ptp, s64 delta) ...@@ -149,9 +150,9 @@ static int mlx4_en_phc_adjtime(struct ptp_clock_info *ptp, s64 delta)
ptp_clock_info); ptp_clock_info);
unsigned long flags; unsigned long flags;
write_lock_irqsave(&mdev->clock_lock, flags); write_seqlock_irqsave(&mdev->clock_lock, flags);
timecounter_adjtime(&mdev->clock, delta); timecounter_adjtime(&mdev->clock, delta);
write_unlock_irqrestore(&mdev->clock_lock, flags); write_sequnlock_irqrestore(&mdev->clock_lock, flags);
return 0; return 0;
} }
...@@ -172,9 +173,9 @@ static int mlx4_en_phc_gettime(struct ptp_clock_info *ptp, ...@@ -172,9 +173,9 @@ static int mlx4_en_phc_gettime(struct ptp_clock_info *ptp,
unsigned long flags; unsigned long flags;
u64 ns; u64 ns;
write_lock_irqsave(&mdev->clock_lock, flags); write_seqlock_irqsave(&mdev->clock_lock, flags);
ns = timecounter_read(&mdev->clock); ns = timecounter_read(&mdev->clock);
write_unlock_irqrestore(&mdev->clock_lock, flags); write_sequnlock_irqrestore(&mdev->clock_lock, flags);
*ts = ns_to_timespec64(ns); *ts = ns_to_timespec64(ns);
...@@ -198,9 +199,9 @@ static int mlx4_en_phc_settime(struct ptp_clock_info *ptp, ...@@ -198,9 +199,9 @@ static int mlx4_en_phc_settime(struct ptp_clock_info *ptp,
unsigned long flags; unsigned long flags;
/* reset the timecounter */ /* reset the timecounter */
write_lock_irqsave(&mdev->clock_lock, flags); write_seqlock_irqsave(&mdev->clock_lock, flags);
timecounter_init(&mdev->clock, &mdev->cycles, ns); timecounter_init(&mdev->clock, &mdev->cycles, ns);
write_unlock_irqrestore(&mdev->clock_lock, flags); write_sequnlock_irqrestore(&mdev->clock_lock, flags);
return 0; return 0;
} }
...@@ -266,7 +267,7 @@ void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev) ...@@ -266,7 +267,7 @@ void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev)
if (mdev->ptp_clock) if (mdev->ptp_clock)
return; return;
rwlock_init(&mdev->clock_lock); seqlock_init(&mdev->clock_lock);
memset(&mdev->cycles, 0, sizeof(mdev->cycles)); memset(&mdev->cycles, 0, sizeof(mdev->cycles));
mdev->cycles.read = mlx4_en_read_clock; mdev->cycles.read = mlx4_en_read_clock;
...@@ -276,10 +277,10 @@ void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev) ...@@ -276,10 +277,10 @@ void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev)
clocksource_khz2mult(1000 * dev->caps.hca_core_clock, mdev->cycles.shift); clocksource_khz2mult(1000 * dev->caps.hca_core_clock, mdev->cycles.shift);
mdev->nominal_c_mult = mdev->cycles.mult; mdev->nominal_c_mult = mdev->cycles.mult;
write_lock_irqsave(&mdev->clock_lock, flags); write_seqlock_irqsave(&mdev->clock_lock, flags);
timecounter_init(&mdev->clock, &mdev->cycles, timecounter_init(&mdev->clock, &mdev->cycles,
ktime_to_ns(ktime_get_real())); ktime_to_ns(ktime_get_real()));
write_unlock_irqrestore(&mdev->clock_lock, flags); write_sequnlock_irqrestore(&mdev->clock_lock, flags);
/* Calculate period in seconds to call the overflow watchdog - to make /* Calculate period in seconds to call the overflow watchdog - to make
* sure counter is checked at least once every wrap around. * sure counter is checked at least once every wrap around.
......
...@@ -424,9 +424,9 @@ struct mlx4_en_dev { ...@@ -424,9 +424,9 @@ struct mlx4_en_dev {
u32 priv_pdn; u32 priv_pdn;
spinlock_t uar_lock; spinlock_t uar_lock;
u8 mac_removed[MLX4_MAX_PORTS + 1]; u8 mac_removed[MLX4_MAX_PORTS + 1];
rwlock_t clock_lock;
u32 nominal_c_mult; u32 nominal_c_mult;
struct cyclecounter cycles; struct cyclecounter cycles;
seqlock_t clock_lock;
struct timecounter clock; struct timecounter clock;
unsigned long last_overflow_check; unsigned long last_overflow_check;
unsigned long overflow_period; unsigned long overflow_period;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment