summaryrefslogtreecommitdiff
path: root/drivers/net/ethernet/pensando/ionic/ionic_phc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/ethernet/pensando/ionic/ionic_phc.c')
-rw-r--r--drivers/net/ethernet/pensando/ionic/ionic_phc.c63
1 files changed, 56 insertions, 7 deletions
diff --git a/drivers/net/ethernet/pensando/ionic/ionic_phc.c b/drivers/net/ethernet/pensando/ionic/ionic_phc.c
index 05b44fc482f8..4b8d80a55b72 100644
--- a/drivers/net/ethernet/pensando/ionic/ionic_phc.c
+++ b/drivers/net/ethernet/pensando/ionic/ionic_phc.c
@@ -3,6 +3,7 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
+#include <uapi/rdma/ib_user_verbs.h>
#include "ionic.h"
#include "ionic_bus.h"
@@ -77,7 +78,8 @@ static int ionic_lif_hwstamp_set_ts_config(struct ionic_lif *lif,
bool rx_all;
__le64 mask;
- if (!lif->phc || !lif->phc->ptp)
+ if (!lif->phc || !lif->phc->ptp ||
+ !(lif->hw_features & IONIC_ETH_HW_TIMESTAMP))
return -EOPNOTSUPP;
mutex_lock(&lif->phc->config_lock);
@@ -210,7 +212,8 @@ int ionic_hwstamp_set(struct net_device *netdev,
struct ionic_lif *lif = netdev_priv(netdev);
int err;
- if (!lif->phc || !lif->phc->ptp)
+ if (!lif->phc || !lif->phc->ptp ||
+ !(lif->hw_features & IONIC_ETH_HW_TIMESTAMP))
return -EOPNOTSUPP;
mutex_lock(&lif->queue_lock);
@@ -228,7 +231,8 @@ void ionic_lif_hwstamp_replay(struct ionic_lif *lif)
{
int err;
- if (!lif->phc || !lif->phc->ptp)
+ if (!lif->phc || !lif->phc->ptp ||
+ !(lif->hw_features & IONIC_ETH_HW_TIMESTAMP))
return;
mutex_lock(&lif->queue_lock);
@@ -242,7 +246,8 @@ void ionic_lif_hwstamp_recreate_queues(struct ionic_lif *lif)
{
int err;
- if (!lif->phc || !lif->phc->ptp)
+ if (!lif->phc || !lif->phc->ptp ||
+ !(lif->hw_features & IONIC_ETH_HW_TIMESTAMP))
return;
mutex_lock(&lif->phc->config_lock);
@@ -267,7 +272,8 @@ int ionic_hwstamp_get(struct net_device *netdev,
{
struct ionic_lif *lif = netdev_priv(netdev);
- if (!lif->phc || !lif->phc->ptp)
+ if (!lif->phc || !lif->phc->ptp ||
+ !(lif->hw_features & IONIC_ETH_HW_TIMESTAMP))
return -EOPNOTSUPP;
mutex_lock(&lif->phc->config_lock);
@@ -329,6 +335,26 @@ static int ionic_setphc_cmd(struct ionic_phc *phc, struct ionic_admin_ctx *ctx)
return ionic_adminq_post(phc->lif, ctx);
}
+static void ionic_phc_state_page_update(struct ionic_phc *phc)
+{
+ struct ib_uverbs_clock_info *state = phc->state_page;
+ u32 sign;
+
+ /* read current sign */
+ sign = smp_load_acquire(&state->sign) & ~1;
+
+ /* make sign odd for updating */
+ smp_store_mb(state->sign, sign | 1);
+
+ state->cycles = phc->tc.cycle_last;
+ state->nsec = phc->tc.nsec;
+ state->frac = phc->tc.frac;
+ state->mult = phc->cc.mult;
+
+ /* make sign the next even number for update completed */
+ smp_store_release(&state->sign, sign + 2);
+}
+
static int ionic_phc_adjfine(struct ptp_clock_info *info, long scaled_ppm)
{
struct ionic_phc *phc = container_of(info, struct ionic_phc, ptp_info);
@@ -356,6 +382,8 @@ static int ionic_phc_adjfine(struct ptp_clock_info *info, long scaled_ppm)
timecounter_read(&phc->tc);
phc->cc.mult = adj;
+ ionic_phc_state_page_update(phc);
+
/* Setphc commands are posted in-order, sequenced by phc->lock. We
* need to drop the lock before waiting for the command to complete.
*/
@@ -381,6 +409,8 @@ static int ionic_phc_adjtime(struct ptp_clock_info *info, s64 delta)
timecounter_adjtime(&phc->tc, delta);
+ ionic_phc_state_page_update(phc);
+
/* Setphc commands are posted in-order, sequenced by phc->lock. We
* need to drop the lock before waiting for the command to complete.
*/
@@ -410,6 +440,8 @@ static int ionic_phc_settime64(struct ptp_clock_info *info,
timecounter_init(&phc->tc, &phc->cc, ns);
+ ionic_phc_state_page_update(phc);
+
/* Setphc commands are posted in-order, sequenced by phc->lock. We
* need to drop the lock before waiting for the command to complete.
*/
@@ -467,6 +499,8 @@ static long ionic_phc_aux_work(struct ptp_clock_info *info)
/* update point-in-time basis to now */
timecounter_read(&phc->tc);
+ ionic_phc_state_page_update(phc);
+
/* Setphc commands are posted in-order, sequenced by phc->lock. We
* need to drop the lock before waiting for the command to complete.
*/
@@ -506,7 +540,8 @@ static const struct ptp_clock_info ionic_ptp_info = {
void ionic_lif_register_phc(struct ionic_lif *lif)
{
- if (!lif->phc || !(lif->hw_features & IONIC_ETH_HW_TIMESTAMP))
+ if (!lif->phc ||
+ !(lif->hw_features & (IONIC_ETH_HW_TIMESTAMP | IONIC_ETH_HW_RDMA_TIMESTAMP)))
return;
lif->phc->ptp = ptp_clock_register(&lif->phc->ptp_info, lif->ionic->dev);
@@ -545,13 +580,19 @@ void ionic_lif_alloc_phc(struct ionic_lif *lif)
return;
features = le64_to_cpu(ionic->ident.lif.eth.config.features);
- if (!(features & IONIC_ETH_HW_TIMESTAMP))
+ if (!(features & (IONIC_ETH_HW_TIMESTAMP | IONIC_ETH_HW_RDMA_TIMESTAMP)))
return;
phc = devm_kzalloc(ionic->dev, sizeof(*phc), GFP_KERNEL);
if (!phc)
return;
+ phc->state_page = (void *)get_zeroed_page(GFP_KERNEL);
+ if (!phc->state_page) {
+ devm_kfree(ionic->dev, phc);
+ return;
+ }
+
phc->lif = lif;
phc->cc.read = ionic_cc_read;
@@ -563,6 +604,7 @@ void ionic_lif_alloc_phc(struct ionic_lif *lif)
dev_err(lif->ionic->dev,
"Invalid device PHC mask multiplier %u, disabling HW timestamp support\n",
phc->cc.mult);
+ free_page((unsigned long)phc->state_page);
devm_kfree(lif->ionic->dev, phc);
lif->phc = NULL;
return;
@@ -646,6 +688,12 @@ void ionic_lif_alloc_phc(struct ionic_lif *lif)
*/
phc->ptp_info.max_adj = NORMAL_PPB;
+ phc->state_page->mask = phc->cc.mask;
+ phc->state_page->shift = phc->cc.shift;
+ phc->state_page->overflow_period = delay;
+
+ ionic_phc_state_page_update(phc);
+
lif->phc = phc;
}
@@ -656,6 +704,7 @@ void ionic_lif_free_phc(struct ionic_lif *lif)
mutex_destroy(&lif->phc->config_lock);
+ free_page((unsigned long)lif->phc->state_page);
devm_kfree(lif->ionic->dev, lif->phc);
lif->phc = NULL;
}