Commit a263f99c authored by David S. Miller's avatar David S. Miller

Merge branch 'Add-ENETC-PTP-clock-driver'

Yangbo Lu says:

====================
Add ENETC PTP clock driver

There is same QorIQ 1588 timer IP block on the new ENETC Ethernet
controller with eTSEC/DPAA Ethernet controllers. However it's
different endianness (little-endian) and using PCI driver.

To support ENETC PTP driver, ptp_qoriq driver needed to be
reworked to make functions global for reusing, to add little-
endian support, to add ENETC memory map support, and to add
ENETC dependency for ptp_qoriq driver.

In addition, although ENETC PTP driver is a PCI driver, the dts
node still could be used. Currently the ls1028a dtsi which is
the only platform by now using ENETC is not complete, so there
is still dependency for ENETC PTP node upstreaming. This will
be done in the near future. The hardware timestamping support
for ENETC is done but needs to be reworked with new method in
internal git tree, and will be sent out soon.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 4ea7b0cf 74abc07d
......@@ -19,6 +19,9 @@ Clock Properties:
- fsl,max-adj Maximum frequency adjustment in parts per billion.
- fsl,extts-fifo The presence of this property indicates hardware
support for the external trigger stamp FIFO.
- little-endian The presence of this property indicates the 1588 timer
IP block is little-endian mode. The default endian mode
is big-endian.
These properties set the operational parameters for the PTP
clock. You must choose these carefully for the clock to work right.
......
......@@ -6104,6 +6104,7 @@ FREESCALE QORIQ PTP CLOCK DRIVER
M: Yangbo Lu <yangbo.lu@nxp.com>
L: netdev@vger.kernel.org
S: Maintained
F: drivers/net/ethernet/freescale/enetc/enetc_ptp.c
F: drivers/ptp/ptp_qoriq.c
F: drivers/ptp/ptp_qoriq_debugfs.c
F: include/linux/fsl/ptp_qoriq.h
......
......@@ -501,7 +501,7 @@ static int dpaa_get_ts_info(struct net_device *net_dev,
struct device_node *mac_node = dev->of_node;
struct device_node *fman_node = NULL, *ptp_node = NULL;
struct platform_device *ptp_dev = NULL;
struct qoriq_ptp *ptp = NULL;
struct ptp_qoriq *ptp = NULL;
info->phc_index = -1;
......
......@@ -17,3 +17,15 @@ config FSL_ENETC_VF
virtual function (VF) devices enabled by the ENETC PF driver.
If compiled as module (M), the module name is fsl-enetc-vf.
config FSL_ENETC_PTP_CLOCK
tristate "ENETC PTP clock driver"
depends on PTP_1588_CLOCK_QORIQ && (FSL_ENETC || FSL_ENETC_VF)
default y
help
This driver adds support for using the ENETC 1588 timer
as a PTP clock. This clock is only useful if your PTP
programs are getting hardware time stamps on the PTP Ethernet
packets using the SO_TIMESTAMPING API.
If compiled as module (M), the module name is fsl-enetc-ptp.
......@@ -13,3 +13,6 @@ fsl-enetc-vf-$(CONFIG_FSL_ENETC_VF) += enetc.o enetc_cbdr.o \
enetc_ethtool.o
fsl-enetc-vf-objs := enetc_vf.o $(fsl-enetc-vf-y)
endif
obj-$(CONFIG_FSL_ENETC_PTP_CLOCK) += fsl-enetc-ptp.o
fsl-enetc-ptp-$(CONFIG_FSL_ENETC_PTP_CLOCK) += enetc_ptp.o
......@@ -4,8 +4,9 @@
#include <linux/bitops.h>
/* ENETC device IDs */
#define ENETC_DEV_ID_PF 0xe100
#define ENETC_DEV_ID_VF 0xef00
#define ENETC_DEV_ID_PF 0xe100
#define ENETC_DEV_ID_VF 0xef00
#define ENETC_DEV_ID_PTP 0xee02
/* ENETC register block BAR */
#define ENETC_BAR_REGS 0
......
// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
/* Copyright 2019 NXP */
#include <linux/module.h>
#include <linux/of.h>
#include <linux/fsl/ptp_qoriq.h>
#include "enetc.h"
static struct ptp_clock_info enetc_ptp_caps = {
.owner = THIS_MODULE,
.name = "ENETC PTP clock",
.max_adj = 512000,
.n_alarm = 0,
.n_ext_ts = 2,
.n_per_out = 0,
.n_pins = 0,
.pps = 1,
.adjfine = ptp_qoriq_adjfine,
.adjtime = ptp_qoriq_adjtime,
.gettime64 = ptp_qoriq_gettime,
.settime64 = ptp_qoriq_settime,
.enable = ptp_qoriq_enable,
};
static int enetc_ptp_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
struct ptp_qoriq *ptp_qoriq;
void __iomem *base;
int err, len, n;
if (pdev->dev.of_node && !of_device_is_available(pdev->dev.of_node)) {
dev_info(&pdev->dev, "device is disabled, skipping\n");
return -ENODEV;
}
err = pci_enable_device_mem(pdev);
if (err) {
dev_err(&pdev->dev, "device enable failed\n");
return err;
}
/* set up for high or low dma */
err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
if (err) {
err = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (err) {
dev_err(&pdev->dev,
"DMA configuration failed: 0x%x\n", err);
goto err_dma;
}
}
err = pci_request_mem_regions(pdev, KBUILD_MODNAME);
if (err) {
dev_err(&pdev->dev, "pci_request_regions failed err=%d\n", err);
goto err_pci_mem_reg;
}
pci_set_master(pdev);
ptp_qoriq = kzalloc(sizeof(*ptp_qoriq), GFP_KERNEL);
if (!ptp_qoriq) {
err = -ENOMEM;
goto err_alloc_ptp;
}
len = pci_resource_len(pdev, ENETC_BAR_REGS);
base = ioremap(pci_resource_start(pdev, ENETC_BAR_REGS), len);
if (!base) {
err = -ENXIO;
dev_err(&pdev->dev, "ioremap() failed\n");
goto err_ioremap;
}
/* Allocate 1 interrupt */
n = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_MSIX);
if (n != 1) {
err = -EPERM;
goto err_irq;
}
ptp_qoriq->irq = pci_irq_vector(pdev, 0);
err = request_irq(ptp_qoriq->irq, ptp_qoriq_isr, 0, DRIVER, ptp_qoriq);
if (err) {
dev_err(&pdev->dev, "request_irq() failed!\n");
goto err_irq;
}
ptp_qoriq->dev = &pdev->dev;
err = ptp_qoriq_init(ptp_qoriq, base, enetc_ptp_caps);
if (err)
goto err_no_clock;
pci_set_drvdata(pdev, ptp_qoriq);
return 0;
err_no_clock:
free_irq(ptp_qoriq->irq, ptp_qoriq);
err_irq:
iounmap(base);
err_ioremap:
kfree(ptp_qoriq);
err_alloc_ptp:
pci_release_mem_regions(pdev);
err_pci_mem_reg:
err_dma:
pci_disable_device(pdev);
return err;
}
static void enetc_ptp_remove(struct pci_dev *pdev)
{
struct ptp_qoriq *ptp_qoriq = pci_get_drvdata(pdev);
ptp_qoriq_free(ptp_qoriq);
kfree(ptp_qoriq);
pci_release_mem_regions(pdev);
pci_disable_device(pdev);
}
static const struct pci_device_id enetc_ptp_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_FREESCALE, ENETC_DEV_ID_PTP) },
{ 0, } /* End of table. */
};
MODULE_DEVICE_TABLE(pci, enetc_ptp_id_table);
static struct pci_driver enetc_ptp_driver = {
.name = KBUILD_MODNAME,
.id_table = enetc_ptp_id_table,
.probe = enetc_ptp_probe,
.remove = enetc_ptp_remove,
};
module_pci_driver(enetc_ptp_driver);
MODULE_DESCRIPTION("ENETC PTP clock driver");
MODULE_LICENSE("Dual BSD/GPL");
......@@ -1492,7 +1492,7 @@ static int gfar_get_ts_info(struct net_device *dev,
struct gfar_private *priv = netdev_priv(dev);
struct platform_device *ptp_dev;
struct device_node *ptp_node;
struct qoriq_ptp *ptp = NULL;
struct ptp_qoriq *ptp = NULL;
info->phc_index = -1;
......
......@@ -617,6 +617,8 @@ static int get_fixed_ipv6_csum(__wsum hw_checksum, struct sk_buff *skb,
}
#endif
#define short_frame(size) ((size) <= ETH_ZLEN + ETH_FCS_LEN)
/* We reach this function only after checking that any of
* the (IPv4 | IPv6) bits are set in cqe->status.
*/
......@@ -624,9 +626,20 @@ static int check_csum(struct mlx4_cqe *cqe, struct sk_buff *skb, void *va,
netdev_features_t dev_features)
{
__wsum hw_checksum = 0;
void *hdr;
/* CQE csum doesn't cover padding octets in short ethernet
* frames. And the pad field is appended prior to calculating
* and appending the FCS field.
*
* Detecting these padded frames requires to verify and parse
* IP headers, so we simply force all those small frames to skip
* checksum complete.
*/
if (short_frame(skb->len))
return -EINVAL;
void *hdr = (u8 *)va + sizeof(struct ethhdr);
hdr = (u8 *)va + sizeof(struct ethhdr);
hw_checksum = csum_unfold((__force __sum16)cqe->checksum);
if (cqe->vlan_my_qpn & cpu_to_be32(MLX4_CQE_CVLAN_PRESENT_MASK) &&
......@@ -819,6 +832,11 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud
skb_record_rx_queue(skb, cq_ring);
if (likely(dev->features & NETIF_F_RXCSUM)) {
/* TODO: For IP non TCP/UDP packets when csum complete is
* not an option (not supported or any other reason) we can
* actually check cqe IPOK status bit and report
* CHECKSUM_UNNECESSARY rather than CHECKSUM_NONE
*/
if ((cqe->status & cpu_to_be16(MLX4_CQE_STATUS_TCP |
MLX4_CQE_STATUS_UDP)) &&
(cqe->status & cpu_to_be16(MLX4_CQE_STATUS_IPOK)) &&
......
......@@ -43,7 +43,7 @@ config PTP_1588_CLOCK_DTE
config PTP_1588_CLOCK_QORIQ
tristate "Freescale QorIQ 1588 timer as PTP clock"
depends on GIANFAR || FSL_DPAA_ETH
depends on GIANFAR || FSL_DPAA_ETH || FSL_ENETC || FSL_ENETC_VF
depends on PTP_1588_CLOCK
default y
help
......
This diff is collapsed.
......@@ -7,11 +7,11 @@
static int ptp_qoriq_fiper1_lpbk_get(void *data, u64 *val)
{
struct qoriq_ptp *qoriq_ptp = data;
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
struct ptp_qoriq *ptp_qoriq = data;
struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
u32 ctrl;
ctrl = qoriq_read(&regs->ctrl_regs->tmr_ctrl);
ctrl = ptp_qoriq->read(&regs->ctrl_regs->tmr_ctrl);
*val = ctrl & PP1L ? 1 : 0;
return 0;
......@@ -19,17 +19,17 @@ static int ptp_qoriq_fiper1_lpbk_get(void *data, u64 *val)
static int ptp_qoriq_fiper1_lpbk_set(void *data, u64 val)
{
struct qoriq_ptp *qoriq_ptp = data;
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
struct ptp_qoriq *ptp_qoriq = data;
struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
u32 ctrl;
ctrl = qoriq_read(&regs->ctrl_regs->tmr_ctrl);
ctrl = ptp_qoriq->read(&regs->ctrl_regs->tmr_ctrl);
if (val == 0)
ctrl &= ~PP1L;
else
ctrl |= PP1L;
qoriq_write(&regs->ctrl_regs->tmr_ctrl, ctrl);
ptp_qoriq->write(&regs->ctrl_regs->tmr_ctrl, ctrl);
return 0;
}
......@@ -38,11 +38,11 @@ DEFINE_DEBUGFS_ATTRIBUTE(ptp_qoriq_fiper1_fops, ptp_qoriq_fiper1_lpbk_get,
static int ptp_qoriq_fiper2_lpbk_get(void *data, u64 *val)
{
struct qoriq_ptp *qoriq_ptp = data;
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
struct ptp_qoriq *ptp_qoriq = data;
struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
u32 ctrl;
ctrl = qoriq_read(&regs->ctrl_regs->tmr_ctrl);
ctrl = ptp_qoriq->read(&regs->ctrl_regs->tmr_ctrl);
*val = ctrl & PP2L ? 1 : 0;
return 0;
......@@ -50,52 +50,52 @@ static int ptp_qoriq_fiper2_lpbk_get(void *data, u64 *val)
static int ptp_qoriq_fiper2_lpbk_set(void *data, u64 val)
{
struct qoriq_ptp *qoriq_ptp = data;
struct qoriq_ptp_registers *regs = &qoriq_ptp->regs;
struct ptp_qoriq *ptp_qoriq = data;
struct ptp_qoriq_registers *regs = &ptp_qoriq->regs;
u32 ctrl;
ctrl = qoriq_read(&regs->ctrl_regs->tmr_ctrl);
ctrl = ptp_qoriq->read(&regs->ctrl_regs->tmr_ctrl);
if (val == 0)
ctrl &= ~PP2L;
else
ctrl |= PP2L;
qoriq_write(&regs->ctrl_regs->tmr_ctrl, ctrl);
ptp_qoriq->write(&regs->ctrl_regs->tmr_ctrl, ctrl);
return 0;
}
DEFINE_DEBUGFS_ATTRIBUTE(ptp_qoriq_fiper2_fops, ptp_qoriq_fiper2_lpbk_get,
ptp_qoriq_fiper2_lpbk_set, "%llu\n");
void ptp_qoriq_create_debugfs(struct qoriq_ptp *qoriq_ptp)
void ptp_qoriq_create_debugfs(struct ptp_qoriq *ptp_qoriq)
{
struct dentry *root;
root = debugfs_create_dir(dev_name(qoriq_ptp->dev), NULL);
root = debugfs_create_dir(dev_name(ptp_qoriq->dev), NULL);
if (IS_ERR(root))
return;
if (!root)
goto err_root;
qoriq_ptp->debugfs_root = root;
ptp_qoriq->debugfs_root = root;
if (!debugfs_create_file_unsafe("fiper1-loopback", 0600, root,
qoriq_ptp, &ptp_qoriq_fiper1_fops))
ptp_qoriq, &ptp_qoriq_fiper1_fops))
goto err_node;
if (!debugfs_create_file_unsafe("fiper2-loopback", 0600, root,
qoriq_ptp, &ptp_qoriq_fiper2_fops))
ptp_qoriq, &ptp_qoriq_fiper2_fops))
goto err_node;
return;
err_node:
debugfs_remove_recursive(root);
qoriq_ptp->debugfs_root = NULL;
ptp_qoriq->debugfs_root = NULL;
err_root:
dev_err(qoriq_ptp->dev, "failed to initialize debugfs\n");
dev_err(ptp_qoriq->dev, "failed to initialize debugfs\n");
}
void ptp_qoriq_remove_debugfs(struct qoriq_ptp *qoriq_ptp)
void ptp_qoriq_remove_debugfs(struct ptp_qoriq *ptp_qoriq)
{
debugfs_remove_recursive(qoriq_ptp->debugfs_root);
qoriq_ptp->debugfs_root = NULL;
debugfs_remove_recursive(ptp_qoriq->debugfs_root);
ptp_qoriq->debugfs_root = NULL;
}
......@@ -7,6 +7,7 @@
#define __PTP_QORIQ_H__
#include <linux/io.h>
#include <linux/interrupt.h>
#include <linux/ptp_clock_kernel.h>
/*
......@@ -49,7 +50,7 @@ struct etts_regs {
u32 tmr_etts2_l; /* Timestamp of general purpose external trigger */
};
struct qoriq_ptp_registers {
struct ptp_qoriq_registers {
struct ctrl_regs __iomem *ctrl_regs;
struct alarm_regs __iomem *alarm_regs;
struct fiper_regs __iomem *fiper_regs;
......@@ -57,15 +58,15 @@ struct qoriq_ptp_registers {
};
/* Offset definitions for the four register groups */
#define CTRL_REGS_OFFSET 0x0
#define ALARM_REGS_OFFSET 0x40
#define FIPER_REGS_OFFSET 0x80
#define ETTS_REGS_OFFSET 0xa0
#define ETSEC_CTRL_REGS_OFFSET 0x0
#define ETSEC_ALARM_REGS_OFFSET 0x40
#define ETSEC_FIPER_REGS_OFFSET 0x80
#define ETSEC_ETTS_REGS_OFFSET 0xa0
#define FMAN_CTRL_REGS_OFFSET 0x80
#define FMAN_ALARM_REGS_OFFSET 0xb8
#define FMAN_FIPER_REGS_OFFSET 0xd0
#define FMAN_ETTS_REGS_OFFSET 0xe0
#define CTRL_REGS_OFFSET 0x80
#define ALARM_REGS_OFFSET 0xb8
#define FIPER_REGS_OFFSET 0xd0
#define ETTS_REGS_OFFSET 0xe0
/* Bit definitions for the TMR_CTRL register */
......@@ -136,9 +137,9 @@ struct qoriq_ptp_registers {
#define DEFAULT_FIPER1_PERIOD 1000000000
#define DEFAULT_FIPER2_PERIOD 100000
struct qoriq_ptp {
struct ptp_qoriq {
void __iomem *base;
struct qoriq_ptp_registers regs;
struct ptp_qoriq_registers regs;
spinlock_t lock; /* protects regs */
struct ptp_clock *clock;
struct ptp_clock_info caps;
......@@ -156,28 +157,48 @@ struct qoriq_ptp {
u32 cksel;
u32 tmr_fiper1;
u32 tmr_fiper2;
u32 (*read)(unsigned __iomem *addr);
void (*write)(unsigned __iomem *addr, u32 val);
};
static inline u32 qoriq_read(unsigned __iomem *addr)
static inline u32 qoriq_read_be(unsigned __iomem *addr)
{
u32 val;
val = ioread32be(addr);
return val;
return ioread32be(addr);
}
static inline void qoriq_write(unsigned __iomem *addr, u32 val)
static inline void qoriq_write_be(unsigned __iomem *addr, u32 val)
{
iowrite32be(val, addr);
}
static inline u32 qoriq_read_le(unsigned __iomem *addr)
{
return ioread32(addr);
}
static inline void qoriq_write_le(unsigned __iomem *addr, u32 val)
{
iowrite32(val, addr);
}
irqreturn_t ptp_qoriq_isr(int irq, void *priv);
int ptp_qoriq_init(struct ptp_qoriq *ptp_qoriq, void __iomem *base,
const struct ptp_clock_info caps);
void ptp_qoriq_free(struct ptp_qoriq *ptp_qoriq);
int ptp_qoriq_adjfine(struct ptp_clock_info *ptp, long scaled_ppm);
int ptp_qoriq_adjtime(struct ptp_clock_info *ptp, s64 delta);
int ptp_qoriq_gettime(struct ptp_clock_info *ptp, struct timespec64 *ts);
int ptp_qoriq_settime(struct ptp_clock_info *ptp,
const struct timespec64 *ts);
int ptp_qoriq_enable(struct ptp_clock_info *ptp,
struct ptp_clock_request *rq, int on);
#ifdef CONFIG_DEBUG_FS
void ptp_qoriq_create_debugfs(struct qoriq_ptp *qoriq_ptp);
void ptp_qoriq_remove_debugfs(struct qoriq_ptp *qoriq_ptp);
void ptp_qoriq_create_debugfs(struct ptp_qoriq *ptp_qoriq);
void ptp_qoriq_remove_debugfs(struct ptp_qoriq *ptp_qoriq);
#else
static inline void ptp_qoriq_create_debugfs(struct qoriq_ptp *qoriq_ptp)
static inline void ptp_qoriq_create_debugfs(struct ptp_qoriq *ptp_qoriq)
{ }
static inline void ptp_qoriq_remove_debugfs(struct qoriq_ptp *qoriq_ptp)
static inline void ptp_qoriq_remove_debugfs(struct ptp_qoriq *ptp_qoriq)
{ }
#endif
......
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