linux/drivers/net/ethernet/broadcom/bnxt/bnxt_ptp.c
<<
>>
Prefs
   1/* Broadcom NetXtreme-C/E network driver.
   2 *
   3 * Copyright (c) 2021 Broadcom Inc.
   4 *
   5 * This program is free software; you can redistribute it and/or modify
   6 * it under the terms of the GNU General Public License as published by
   7 * the Free Software Foundation.
   8 */
   9#include <linux/kernel.h>
  10#include <linux/errno.h>
  11#include <linux/pci.h>
  12#include <linux/netdevice.h>
  13#include <linux/etherdevice.h>
  14#include <linux/ptp_clock_kernel.h>
  15#include <linux/net_tstamp.h>
  16#include <linux/timecounter.h>
  17#include <linux/timekeeping.h>
  18#include <linux/ptp_classify.h>
  19#include "bnxt_hsi.h"
  20#include "bnxt.h"
  21#include "bnxt_ptp.h"
  22
  23int bnxt_ptp_parse(struct sk_buff *skb, u16 *seq_id, u16 *hdr_off)
  24{
  25        unsigned int ptp_class;
  26        struct ptp_header *hdr;
  27
  28        ptp_class = ptp_classify_raw(skb);
  29
  30        switch (ptp_class & PTP_CLASS_VMASK) {
  31        case PTP_CLASS_V1:
  32        case PTP_CLASS_V2:
  33                hdr = ptp_parse_header(skb, ptp_class);
  34                if (!hdr)
  35                        return -EINVAL;
  36
  37                *hdr_off = (u8 *)hdr - skb->data;
  38                *seq_id  = ntohs(hdr->sequence_id);
  39                return 0;
  40        default:
  41                return -ERANGE;
  42        }
  43}
  44
  45static int bnxt_ptp_settime(struct ptp_clock_info *ptp_info,
  46                            const struct timespec64 *ts)
  47{
  48        struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
  49                                                ptp_info);
  50        u64 ns = timespec64_to_ns(ts);
  51
  52        spin_lock_bh(&ptp->ptp_lock);
  53        timecounter_init(&ptp->tc, &ptp->cc, ns);
  54        spin_unlock_bh(&ptp->ptp_lock);
  55        return 0;
  56}
  57
  58/* Caller holds ptp_lock */
  59static u64 bnxt_refclk_read(struct bnxt *bp, struct ptp_system_timestamp *sts)
  60{
  61        struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
  62        u64 ns;
  63
  64        ptp_read_system_prets(sts);
  65        ns = readl(bp->bar0 + ptp->refclk_mapped_regs[0]);
  66        ptp_read_system_postts(sts);
  67        ns |= (u64)readl(bp->bar0 + ptp->refclk_mapped_regs[1]) << 32;
  68        return ns;
  69}
  70
  71static void bnxt_ptp_get_current_time(struct bnxt *bp)
  72{
  73        struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
  74
  75        if (!ptp)
  76                return;
  77        spin_lock_bh(&ptp->ptp_lock);
  78        WRITE_ONCE(ptp->old_time, ptp->current_time);
  79        ptp->current_time = bnxt_refclk_read(bp, NULL);
  80        spin_unlock_bh(&ptp->ptp_lock);
  81}
  82
  83static int bnxt_hwrm_port_ts_query(struct bnxt *bp, u32 flags, u64 *ts)
  84{
  85        struct hwrm_port_ts_query_output *resp = bp->hwrm_cmd_resp_addr;
  86        struct hwrm_port_ts_query_input req = {0};
  87        int rc;
  88
  89        bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_TS_QUERY, -1, -1);
  90        req.flags = cpu_to_le32(flags);
  91        if ((flags & PORT_TS_QUERY_REQ_FLAGS_PATH) ==
  92            PORT_TS_QUERY_REQ_FLAGS_PATH_TX) {
  93                req.enables = cpu_to_le16(BNXT_PTP_QTS_TX_ENABLES);
  94                req.ptp_seq_id = cpu_to_le32(bp->ptp_cfg->tx_seqid);
  95                req.ptp_hdr_offset = cpu_to_le16(bp->ptp_cfg->tx_hdr_off);
  96                req.ts_req_timeout = cpu_to_le16(BNXT_PTP_QTS_TIMEOUT);
  97        }
  98        mutex_lock(&bp->hwrm_cmd_lock);
  99        rc = _hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
 100        if (!rc)
 101                *ts = le64_to_cpu(resp->ptp_msg_ts);
 102        mutex_unlock(&bp->hwrm_cmd_lock);
 103        return rc;
 104}
 105
 106static int bnxt_ptp_gettimex(struct ptp_clock_info *ptp_info,
 107                             struct timespec64 *ts,
 108                             struct ptp_system_timestamp *sts)
 109{
 110        struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
 111                                                ptp_info);
 112        u64 ns, cycles;
 113
 114        spin_lock_bh(&ptp->ptp_lock);
 115        cycles = bnxt_refclk_read(ptp->bp, sts);
 116        ns = timecounter_cyc2time(&ptp->tc, cycles);
 117        spin_unlock_bh(&ptp->ptp_lock);
 118        *ts = ns_to_timespec64(ns);
 119
 120        return 0;
 121}
 122
 123static int bnxt_ptp_adjtime(struct ptp_clock_info *ptp_info, s64 delta)
 124{
 125        struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
 126                                                ptp_info);
 127
 128        spin_lock_bh(&ptp->ptp_lock);
 129        timecounter_adjtime(&ptp->tc, delta);
 130        spin_unlock_bh(&ptp->ptp_lock);
 131        return 0;
 132}
 133
 134static int bnxt_ptp_adjfreq(struct ptp_clock_info *ptp_info, s32 ppb)
 135{
 136        struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
 137                                                ptp_info);
 138        struct hwrm_port_mac_cfg_input req = {0};
 139        struct bnxt *bp = ptp->bp;
 140        int rc;
 141
 142        bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_MAC_CFG, -1, -1);
 143        req.ptp_freq_adj_ppb = cpu_to_le32(ppb);
 144        req.enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_PTP_FREQ_ADJ_PPB);
 145        rc = hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
 146        if (rc)
 147                netdev_err(ptp->bp->dev,
 148                           "ptp adjfreq failed. rc = %d\n", rc);
 149        return rc;
 150}
 151
 152static int bnxt_ptp_enable(struct ptp_clock_info *ptp,
 153                           struct ptp_clock_request *rq, int on)
 154{
 155        return -EOPNOTSUPP;
 156}
 157
 158static int bnxt_hwrm_ptp_cfg(struct bnxt *bp)
 159{
 160        struct hwrm_port_mac_cfg_input req = {0};
 161        struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
 162        u32 flags = 0;
 163
 164        bnxt_hwrm_cmd_hdr_init(bp, &req, HWRM_PORT_MAC_CFG, -1, -1);
 165        if (ptp->rx_filter)
 166                flags |= PORT_MAC_CFG_REQ_FLAGS_PTP_RX_TS_CAPTURE_ENABLE;
 167        else
 168                flags |= PORT_MAC_CFG_REQ_FLAGS_PTP_RX_TS_CAPTURE_DISABLE;
 169        if (ptp->tx_tstamp_en)
 170                flags |= PORT_MAC_CFG_REQ_FLAGS_PTP_TX_TS_CAPTURE_ENABLE;
 171        else
 172                flags |= PORT_MAC_CFG_REQ_FLAGS_PTP_TX_TS_CAPTURE_DISABLE;
 173        req.flags = cpu_to_le32(flags);
 174        req.enables = cpu_to_le32(PORT_MAC_CFG_REQ_ENABLES_RX_TS_CAPTURE_PTP_MSG_TYPE);
 175        req.rx_ts_capture_ptp_msg_type = cpu_to_le16(ptp->rxctl);
 176
 177        return hwrm_send_message(bp, &req, sizeof(req), HWRM_CMD_TIMEOUT);
 178}
 179
 180int bnxt_hwtstamp_set(struct net_device *dev, struct ifreq *ifr)
 181{
 182        struct bnxt *bp = netdev_priv(dev);
 183        struct hwtstamp_config stmpconf;
 184        struct bnxt_ptp_cfg *ptp;
 185        u16 old_rxctl;
 186        int old_rx_filter, rc;
 187        u8 old_tx_tstamp_en;
 188
 189        ptp = bp->ptp_cfg;
 190        if (!ptp)
 191                return -EOPNOTSUPP;
 192
 193        if (copy_from_user(&stmpconf, ifr->ifr_data, sizeof(stmpconf)))
 194                return -EFAULT;
 195
 196        if (stmpconf.flags)
 197                return -EINVAL;
 198
 199        if (stmpconf.tx_type != HWTSTAMP_TX_ON &&
 200            stmpconf.tx_type != HWTSTAMP_TX_OFF)
 201                return -ERANGE;
 202
 203        old_rx_filter = ptp->rx_filter;
 204        old_rxctl = ptp->rxctl;
 205        old_tx_tstamp_en = ptp->tx_tstamp_en;
 206        switch (stmpconf.rx_filter) {
 207        case HWTSTAMP_FILTER_NONE:
 208                ptp->rxctl = 0;
 209                ptp->rx_filter = HWTSTAMP_FILTER_NONE;
 210                break;
 211        case HWTSTAMP_FILTER_PTP_V2_EVENT:
 212        case HWTSTAMP_FILTER_PTP_V2_L2_EVENT:
 213        case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
 214                ptp->rxctl = BNXT_PTP_MSG_EVENTS;
 215                ptp->rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
 216                break;
 217        case HWTSTAMP_FILTER_PTP_V2_SYNC:
 218        case HWTSTAMP_FILTER_PTP_V2_L2_SYNC:
 219        case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
 220                ptp->rxctl = BNXT_PTP_MSG_SYNC;
 221                ptp->rx_filter = HWTSTAMP_FILTER_PTP_V2_SYNC;
 222                break;
 223        case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
 224        case HWTSTAMP_FILTER_PTP_V2_L2_DELAY_REQ:
 225        case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
 226                ptp->rxctl = BNXT_PTP_MSG_DELAY_REQ;
 227                ptp->rx_filter = HWTSTAMP_FILTER_PTP_V2_DELAY_REQ;
 228                break;
 229        default:
 230                return -ERANGE;
 231        }
 232
 233        if (stmpconf.tx_type == HWTSTAMP_TX_ON)
 234                ptp->tx_tstamp_en = 1;
 235        else
 236                ptp->tx_tstamp_en = 0;
 237
 238        rc = bnxt_hwrm_ptp_cfg(bp);
 239        if (rc)
 240                goto ts_set_err;
 241
 242        stmpconf.rx_filter = ptp->rx_filter;
 243        return copy_to_user(ifr->ifr_data, &stmpconf, sizeof(stmpconf)) ?
 244                -EFAULT : 0;
 245
 246ts_set_err:
 247        ptp->rx_filter = old_rx_filter;
 248        ptp->rxctl = old_rxctl;
 249        ptp->tx_tstamp_en = old_tx_tstamp_en;
 250        return rc;
 251}
 252
 253int bnxt_hwtstamp_get(struct net_device *dev, struct ifreq *ifr)
 254{
 255        struct bnxt *bp = netdev_priv(dev);
 256        struct hwtstamp_config stmpconf;
 257        struct bnxt_ptp_cfg *ptp;
 258
 259        ptp = bp->ptp_cfg;
 260        if (!ptp)
 261                return -EOPNOTSUPP;
 262
 263        stmpconf.flags = 0;
 264        stmpconf.tx_type = ptp->tx_tstamp_en ? HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
 265
 266        stmpconf.rx_filter = ptp->rx_filter;
 267        return copy_to_user(ifr->ifr_data, &stmpconf, sizeof(stmpconf)) ?
 268                -EFAULT : 0;
 269}
 270
 271static int bnxt_map_regs(struct bnxt *bp, u32 *reg_arr, int count, int reg_win)
 272{
 273        u32 reg_base = *reg_arr & BNXT_GRC_BASE_MASK;
 274        u32 win_off;
 275        int i;
 276
 277        for (i = 0; i < count; i++) {
 278                if ((reg_arr[i] & BNXT_GRC_BASE_MASK) != reg_base)
 279                        return -ERANGE;
 280        }
 281        win_off = BNXT_GRCPF_REG_WINDOW_BASE_OUT + (reg_win - 1) * 4;
 282        writel(reg_base, bp->bar0 + win_off);
 283        return 0;
 284}
 285
 286static int bnxt_map_ptp_regs(struct bnxt *bp)
 287{
 288        struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
 289        u32 *reg_arr;
 290        int rc, i;
 291
 292        reg_arr = ptp->refclk_regs;
 293        if (bp->flags & BNXT_FLAG_CHIP_P5) {
 294                rc = bnxt_map_regs(bp, reg_arr, 2, BNXT_PTP_GRC_WIN);
 295                if (rc)
 296                        return rc;
 297                for (i = 0; i < 2; i++)
 298                        ptp->refclk_mapped_regs[i] = BNXT_PTP_GRC_WIN_BASE +
 299                                (ptp->refclk_regs[i] & BNXT_GRC_OFFSET_MASK);
 300                return 0;
 301        }
 302        return -ENODEV;
 303}
 304
 305static void bnxt_unmap_ptp_regs(struct bnxt *bp)
 306{
 307        writel(0, bp->bar0 + BNXT_GRCPF_REG_WINDOW_BASE_OUT +
 308                  (BNXT_PTP_GRC_WIN - 1) * 4);
 309}
 310
 311static u64 bnxt_cc_read(const struct cyclecounter *cc)
 312{
 313        struct bnxt_ptp_cfg *ptp = container_of(cc, struct bnxt_ptp_cfg, cc);
 314
 315        return bnxt_refclk_read(ptp->bp, NULL);
 316}
 317
 318static void bnxt_stamp_tx_skb(struct bnxt *bp, struct sk_buff *skb)
 319{
 320        struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
 321        struct skb_shared_hwtstamps timestamp;
 322        u64 ts = 0, ns = 0;
 323        int rc;
 324
 325        rc = bnxt_hwrm_port_ts_query(bp, PORT_TS_QUERY_REQ_FLAGS_PATH_TX, &ts);
 326        if (!rc) {
 327                memset(&timestamp, 0, sizeof(timestamp));
 328                spin_lock_bh(&ptp->ptp_lock);
 329                ns = timecounter_cyc2time(&ptp->tc, ts);
 330                spin_unlock_bh(&ptp->ptp_lock);
 331                timestamp.hwtstamp = ns_to_ktime(ns);
 332                skb_tstamp_tx(ptp->tx_skb, &timestamp);
 333        } else {
 334                netdev_err(bp->dev, "TS query for TX timer failed rc = %x\n",
 335                           rc);
 336        }
 337
 338        dev_kfree_skb_any(ptp->tx_skb);
 339        ptp->tx_skb = NULL;
 340        atomic_inc(&ptp->tx_avail);
 341}
 342
 343static long bnxt_ptp_ts_aux_work(struct ptp_clock_info *ptp_info)
 344{
 345        struct bnxt_ptp_cfg *ptp = container_of(ptp_info, struct bnxt_ptp_cfg,
 346                                                ptp_info);
 347        unsigned long now = jiffies;
 348        struct bnxt *bp = ptp->bp;
 349
 350        if (ptp->tx_skb)
 351                bnxt_stamp_tx_skb(bp, ptp->tx_skb);
 352
 353        if (!time_after_eq(now, ptp->next_period))
 354                return ptp->next_period - now;
 355
 356        bnxt_ptp_get_current_time(bp);
 357        ptp->next_period = now + HZ;
 358        if (time_after_eq(now, ptp->next_overflow_check)) {
 359                spin_lock_bh(&ptp->ptp_lock);
 360                timecounter_read(&ptp->tc);
 361                spin_unlock_bh(&ptp->ptp_lock);
 362                ptp->next_overflow_check = now + BNXT_PHC_OVERFLOW_PERIOD;
 363        }
 364        return HZ;
 365}
 366
 367int bnxt_get_tx_ts_p5(struct bnxt *bp, struct sk_buff *skb)
 368{
 369        struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
 370
 371        if (ptp->tx_skb) {
 372                netdev_err(bp->dev, "deferring skb:one SKB is still outstanding\n");
 373                return -EBUSY;
 374        }
 375        ptp->tx_skb = skb;
 376        ptp_schedule_worker(ptp->ptp_clock, 0);
 377        return 0;
 378}
 379
 380int bnxt_get_rx_ts_p5(struct bnxt *bp, u64 *ts, u32 pkt_ts)
 381{
 382        struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
 383        u64 time;
 384
 385        if (!ptp)
 386                return -ENODEV;
 387
 388        BNXT_READ_TIME64(ptp, time, ptp->old_time);
 389        *ts = (time & BNXT_HI_TIMER_MASK) | pkt_ts;
 390        if (pkt_ts < (time & BNXT_LO_TIMER_MASK))
 391                *ts += BNXT_LO_TIMER_MASK + 1;
 392
 393        return 0;
 394}
 395
 396static const struct ptp_clock_info bnxt_ptp_caps = {
 397        .owner          = THIS_MODULE,
 398        .name           = "bnxt clock",
 399        .max_adj        = BNXT_MAX_PHC_DRIFT,
 400        .n_alarm        = 0,
 401        .n_ext_ts       = 0,
 402        .n_per_out      = 0,
 403        .n_pins         = 0,
 404        .pps            = 0,
 405        .adjfreq        = bnxt_ptp_adjfreq,
 406        .adjtime        = bnxt_ptp_adjtime,
 407        .do_aux_work    = bnxt_ptp_ts_aux_work,
 408        .gettimex64     = bnxt_ptp_gettimex,
 409        .settime64      = bnxt_ptp_settime,
 410        .enable         = bnxt_ptp_enable,
 411};
 412
 413int bnxt_ptp_init(struct bnxt *bp)
 414{
 415        struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
 416        int rc;
 417
 418        if (!ptp)
 419                return 0;
 420
 421        rc = bnxt_map_ptp_regs(bp);
 422        if (rc)
 423                return rc;
 424
 425        atomic_set(&ptp->tx_avail, BNXT_MAX_TX_TS);
 426        spin_lock_init(&ptp->ptp_lock);
 427
 428        memset(&ptp->cc, 0, sizeof(ptp->cc));
 429        ptp->cc.read = bnxt_cc_read;
 430        ptp->cc.mask = CYCLECOUNTER_MASK(48);
 431        ptp->cc.shift = 0;
 432        ptp->cc.mult = 1;
 433
 434        ptp->next_overflow_check = jiffies + BNXT_PHC_OVERFLOW_PERIOD;
 435        timecounter_init(&ptp->tc, &ptp->cc, ktime_to_ns(ktime_get_real()));
 436
 437        ptp->ptp_info = bnxt_ptp_caps;
 438        ptp->ptp_clock = ptp_clock_register(&ptp->ptp_info, &bp->pdev->dev);
 439        if (IS_ERR(ptp->ptp_clock)) {
 440                int err = PTR_ERR(ptp->ptp_clock);
 441
 442                ptp->ptp_clock = NULL;
 443                bnxt_unmap_ptp_regs(bp);
 444                return err;
 445        }
 446        if (bp->flags & BNXT_FLAG_CHIP_P5) {
 447                spin_lock_bh(&ptp->ptp_lock);
 448                ptp->current_time = bnxt_refclk_read(bp, NULL);
 449                WRITE_ONCE(ptp->old_time, ptp->current_time);
 450                spin_unlock_bh(&ptp->ptp_lock);
 451                ptp_schedule_worker(ptp->ptp_clock, 0);
 452        }
 453        return 0;
 454}
 455
 456void bnxt_ptp_clear(struct bnxt *bp)
 457{
 458        struct bnxt_ptp_cfg *ptp = bp->ptp_cfg;
 459
 460        if (!ptp)
 461                return;
 462
 463        if (ptp->ptp_clock)
 464                ptp_clock_unregister(ptp->ptp_clock);
 465
 466        ptp->ptp_clock = NULL;
 467        if (ptp->tx_skb) {
 468                dev_kfree_skb_any(ptp->tx_skb);
 469                ptp->tx_skb = NULL;
 470        }
 471        bnxt_unmap_ptp_regs(bp);
 472}
 473