Commit 97083c21 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge tag 'linux-can-next-for-6.6-20230719' of...

Merge tag 'linux-can-next-for-6.6-20230719' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next

Marc Kleine-Budde says:

====================
pull-request: can-next 2023-07-19

The first 2 patches are by Judith Mendez, target the m_can driver and
add hrtimer based polling support for TI AM62x SoCs, where the
interrupt of the MCU domain's m_can cores is not routed to the Cortex
A53 core.

A patch by Rob Herring converts the grcan driver to use the correct DT
include files.

Michal Simek and Srinivas Neeli add support for optional reset control
to the xilinx_can driver.

The next 2 patches are by Jimmy Assarsson and add support for new
Kvaser pciefd to the kvaser_pciefd driver.

Mao Zhu's patch for the ucan driver removes a repeated word from a
comment.

* tag 'linux-can-next-for-6.6-20230719' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next:
  can: ucan: Remove repeated word
  can: kvaser_pciefd: Add support for new Kvaser pciefd devices
  can: kvaser_pciefd: Move hardware specific constants and functions into a driver_data struct
  can: Explicitly include correct DT includes
  can: xilinx_can: Add support for controller reset
  dt-bindings: can: xilinx_can: Add reset description
  can: m_can: Add hrtimer to generate software interrupt
  dt-bindings: net: can: Remove interrupt properties for MCAN
====================

Link: https://lore.kernel.org/r/20230719072348.525039-1-mkl@pengutronix.deSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 36395b2e 03df47c1
...@@ -122,8 +122,6 @@ required: ...@@ -122,8 +122,6 @@ required:
- compatible - compatible
- reg - reg
- reg-names - reg-names
- interrupts
- interrupt-names
- clocks - clocks
- clock-names - clock-names
- bosch,mram-cfg - bosch,mram-cfg
...@@ -132,6 +130,7 @@ additionalProperties: false ...@@ -132,6 +130,7 @@ additionalProperties: false
examples: examples:
- | - |
// Example with interrupts
#include <dt-bindings/clock/imx6sx-clock.h> #include <dt-bindings/clock/imx6sx-clock.h>
can@20e8000 { can@20e8000 {
compatible = "bosch,m_can"; compatible = "bosch,m_can";
...@@ -149,4 +148,21 @@ examples: ...@@ -149,4 +148,21 @@ examples:
}; };
}; };
- |
// Example with timer polling
#include <dt-bindings/clock/imx6sx-clock.h>
can@20e8000 {
compatible = "bosch,m_can";
reg = <0x020e8000 0x4000>, <0x02298000 0x4000>;
reg-names = "m_can", "message_ram";
clocks = <&clks IMX6SX_CLK_CANFD>,
<&clks IMX6SX_CLK_CANFD>;
clock-names = "hclk", "cclk";
bosch,mram-cfg = <0x0 0 0 32 0 0 0 1>;
can-transceiver {
max-bitrate = <5000000>;
};
};
... ...
...@@ -46,6 +46,9 @@ properties: ...@@ -46,6 +46,9 @@ properties:
$ref: /schemas/types.yaml#/definitions/uint32 $ref: /schemas/types.yaml#/definitions/uint32
description: CAN Tx mailbox buffer count (CAN FD) description: CAN Tx mailbox buffer count (CAN FD)
resets:
maxItems: 1
required: required:
- compatible - compatible
- reg - reg
......
...@@ -160,8 +160,13 @@ config CAN_KVASER_PCIEFD ...@@ -160,8 +160,13 @@ config CAN_KVASER_PCIEFD
Kvaser PCIEcan 4xHS Kvaser PCIEcan 4xHS
Kvaser PCIEcan 2xHS v2 Kvaser PCIEcan 2xHS v2
Kvaser PCIEcan HS v2 Kvaser PCIEcan HS v2
Kvaser PCIEcan 1xCAN v3
Kvaser PCIEcan 2xCAN v3
Kvaser PCIEcan 4xCAN v2
Kvaser Mini PCI Express HS v2 Kvaser Mini PCI Express HS v2
Kvaser Mini PCI Express 2xHS v2 Kvaser Mini PCI Express 2xHS v2
Kvaser Mini PCI Express 1xCAN v3
Kvaser Mini PCI Express 2xCAN v3
config CAN_SLCAN config CAN_SLCAN
tristate "Serial / USB serial CAN Adaptors (slcan)" tristate "Serial / USB serial CAN Adaptors (slcan)"
......
...@@ -30,8 +30,9 @@ ...@@ -30,8 +30,9 @@
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/of_platform.h> #include <linux/of.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
......
// SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause // SPDX-License-Identifier: GPL-2.0 OR BSD-2-Clause
/* Copyright (C) 2018 KVASER AB, Sweden. All rights reserved. /* Copyright (C) 2018 KVASER AB, Sweden. All rights reserved.
* Parts of this driver are based on the following: * Parts of this driver are based on the following:
* - Kvaser linux pciefd driver (version 5.25) * - Kvaser linux pciefd driver (version 5.42)
* - PEAK linux canfd driver * - PEAK linux canfd driver
*/ */
...@@ -33,37 +33,27 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); ...@@ -33,37 +33,27 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices");
#define KVASER_PCIEFD_DMA_SIZE (4U * 1024U) #define KVASER_PCIEFD_DMA_SIZE (4U * 1024U)
#define KVASER_PCIEFD_VENDOR 0x1a07 #define KVASER_PCIEFD_VENDOR 0x1a07
/* Altera based devices */
#define KVASER_PCIEFD_4HS_DEVICE_ID 0x000d #define KVASER_PCIEFD_4HS_DEVICE_ID 0x000d
#define KVASER_PCIEFD_2HS_V2_DEVICE_ID 0x000e #define KVASER_PCIEFD_2HS_V2_DEVICE_ID 0x000e
#define KVASER_PCIEFD_HS_V2_DEVICE_ID 0x000f #define KVASER_PCIEFD_HS_V2_DEVICE_ID 0x000f
#define KVASER_PCIEFD_MINIPCIE_HS_V2_DEVICE_ID 0x0010 #define KVASER_PCIEFD_MINIPCIE_HS_V2_DEVICE_ID 0x0010
#define KVASER_PCIEFD_MINIPCIE_2HS_V2_DEVICE_ID 0x0011 #define KVASER_PCIEFD_MINIPCIE_2HS_V2_DEVICE_ID 0x0011
/* PCIe IRQ registers */ /* SmartFusion2 based devices */
#define KVASER_PCIEFD_IRQ_REG 0x40 #define KVASER_PCIEFD_2CAN_V3_DEVICE_ID 0x0012
#define KVASER_PCIEFD_IEN_REG 0x50 #define KVASER_PCIEFD_1CAN_V3_DEVICE_ID 0x0013
/* DMA address translation map register base */ #define KVASER_PCIEFD_4CAN_V2_DEVICE_ID 0x0014
#define KVASER_PCIEFD_DMA_MAP_BASE 0x1000 #define KVASER_PCIEFD_MINIPCIE_2CAN_V3_DEVICE_ID 0x0015
/* Loopback control register */ #define KVASER_PCIEFD_MINIPCIE_1CAN_V3_DEVICE_ID 0x0016
#define KVASER_PCIEFD_LOOP_REG 0x1f000
/* System identification and information registers */ /* Altera SerDes Enable 64-bit DMA address translation */
#define KVASER_PCIEFD_SYSID_BASE 0x1f020 #define KVASER_PCIEFD_ALTERA_DMA_64BIT BIT(0)
#define KVASER_PCIEFD_SYSID_VERSION_REG (KVASER_PCIEFD_SYSID_BASE + 0x8)
#define KVASER_PCIEFD_SYSID_CANFREQ_REG (KVASER_PCIEFD_SYSID_BASE + 0xc) /* SmartFusion2 SerDes LSB address translation mask */
#define KVASER_PCIEFD_SYSID_BUSFREQ_REG (KVASER_PCIEFD_SYSID_BASE + 0x10) #define KVASER_PCIEFD_SF2_DMA_LSB_MASK GENMASK(31, 12)
#define KVASER_PCIEFD_SYSID_BUILD_REG (KVASER_PCIEFD_SYSID_BASE + 0x14)
/* Shared receive buffer registers */
#define KVASER_PCIEFD_SRB_BASE 0x1f200
#define KVASER_PCIEFD_SRB_FIFO_LAST_REG (KVASER_PCIEFD_SRB_BASE + 0x1f4)
#define KVASER_PCIEFD_SRB_CMD_REG (KVASER_PCIEFD_SRB_BASE + 0x200)
#define KVASER_PCIEFD_SRB_IEN_REG (KVASER_PCIEFD_SRB_BASE + 0x204)
#define KVASER_PCIEFD_SRB_IRQ_REG (KVASER_PCIEFD_SRB_BASE + 0x20c)
#define KVASER_PCIEFD_SRB_STAT_REG (KVASER_PCIEFD_SRB_BASE + 0x210)
#define KVASER_PCIEFD_SRB_RX_NR_PACKETS_REG (KVASER_PCIEFD_SRB_BASE + 0x214)
#define KVASER_PCIEFD_SRB_CTRL_REG (KVASER_PCIEFD_SRB_BASE + 0x218)
/* Kvaser KCAN CAN controller registers */ /* Kvaser KCAN CAN controller registers */
#define KVASER_PCIEFD_KCAN0_BASE 0x10000
#define KVASER_PCIEFD_KCAN_BASE_OFFSET 0x1000
#define KVASER_PCIEFD_KCAN_FIFO_REG 0x100 #define KVASER_PCIEFD_KCAN_FIFO_REG 0x100
#define KVASER_PCIEFD_KCAN_FIFO_LAST_REG 0x180 #define KVASER_PCIEFD_KCAN_FIFO_LAST_REG 0x180
#define KVASER_PCIEFD_KCAN_CTRL_REG 0x2c0 #define KVASER_PCIEFD_KCAN_CTRL_REG 0x2c0
...@@ -77,13 +67,20 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); ...@@ -77,13 +67,20 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices");
#define KVASER_PCIEFD_KCAN_BUS_LOAD_REG 0x424 #define KVASER_PCIEFD_KCAN_BUS_LOAD_REG 0x424
#define KVASER_PCIEFD_KCAN_BTRD_REG 0x428 #define KVASER_PCIEFD_KCAN_BTRD_REG 0x428
#define KVASER_PCIEFD_KCAN_PWM_REG 0x430 #define KVASER_PCIEFD_KCAN_PWM_REG 0x430
/* System identification and information registers */
/* PCI interrupt fields */ #define KVASER_PCIEFD_SYSID_VERSION_REG 0x8
#define KVASER_PCIEFD_IRQ_SRB BIT(4) #define KVASER_PCIEFD_SYSID_CANFREQ_REG 0xc
#define KVASER_PCIEFD_IRQ_ALL_MASK GENMASK(4, 0) #define KVASER_PCIEFD_SYSID_BUSFREQ_REG 0x10
#define KVASER_PCIEFD_SYSID_BUILD_REG 0x14
/* Enable 64-bit DMA address translation */ /* Shared receive buffer FIFO registers */
#define KVASER_PCIEFD_64BIT_DMA_BIT BIT(0) #define KVASER_PCIEFD_SRB_FIFO_LAST_REG 0x1f4
/* Shared receive buffer registers */
#define KVASER_PCIEFD_SRB_CMD_REG 0x0
#define KVASER_PCIEFD_SRB_IEN_REG 0x04
#define KVASER_PCIEFD_SRB_IRQ_REG 0x0c
#define KVASER_PCIEFD_SRB_STAT_REG 0x10
#define KVASER_PCIEFD_SRB_RX_NR_PACKETS_REG 0x14
#define KVASER_PCIEFD_SRB_CTRL_REG 0x18
/* System build information fields */ /* System build information fields */
#define KVASER_PCIEFD_SYSID_VERSION_NR_CHAN_MASK GENMASK(31, 24) #define KVASER_PCIEFD_SYSID_VERSION_NR_CHAN_MASK GENMASK(31, 24)
...@@ -253,7 +250,122 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices"); ...@@ -253,7 +250,122 @@ MODULE_DESCRIPTION("CAN driver for Kvaser CAN/PCIe devices");
/* KCAN Error detected packet, second word */ /* KCAN Error detected packet, second word */
#define KVASER_PCIEFD_EPACK_DIR_TX BIT(0) #define KVASER_PCIEFD_EPACK_DIR_TX BIT(0)
/* Macros for calculating addresses of registers */
#define KVASER_PCIEFD_GET_BLOCK_ADDR(pcie, block) \
((pcie)->reg_base + (pcie)->driver_data->address_offset->block)
#define KVASER_PCIEFD_PCI_IEN_ADDR(pcie) \
(KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), pci_ien))
#define KVASER_PCIEFD_PCI_IRQ_ADDR(pcie) \
(KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), pci_irq))
#define KVASER_PCIEFD_SERDES_ADDR(pcie) \
(KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), serdes))
#define KVASER_PCIEFD_SYSID_ADDR(pcie) \
(KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), sysid))
#define KVASER_PCIEFD_LOOPBACK_ADDR(pcie) \
(KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), loopback))
#define KVASER_PCIEFD_SRB_FIFO_ADDR(pcie) \
(KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), kcan_srb_fifo))
#define KVASER_PCIEFD_SRB_ADDR(pcie) \
(KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), kcan_srb))
#define KVASER_PCIEFD_KCAN_CH0_ADDR(pcie) \
(KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), kcan_ch0))
#define KVASER_PCIEFD_KCAN_CH1_ADDR(pcie) \
(KVASER_PCIEFD_GET_BLOCK_ADDR((pcie), kcan_ch1))
#define KVASER_PCIEFD_KCAN_CHANNEL_SPAN(pcie) \
(KVASER_PCIEFD_KCAN_CH1_ADDR((pcie)) - KVASER_PCIEFD_KCAN_CH0_ADDR((pcie)))
#define KVASER_PCIEFD_KCAN_CHX_ADDR(pcie, i) \
(KVASER_PCIEFD_KCAN_CH0_ADDR((pcie)) + (i) * KVASER_PCIEFD_KCAN_CHANNEL_SPAN((pcie)))
struct kvaser_pciefd; struct kvaser_pciefd;
static void kvaser_pciefd_write_dma_map_altera(struct kvaser_pciefd *pcie,
dma_addr_t addr, int index);
static void kvaser_pciefd_write_dma_map_sf2(struct kvaser_pciefd *pcie,
dma_addr_t addr, int index);
struct kvaser_pciefd_address_offset {
u32 serdes;
u32 pci_ien;
u32 pci_irq;
u32 sysid;
u32 loopback;
u32 kcan_srb_fifo;
u32 kcan_srb;
u32 kcan_ch0;
u32 kcan_ch1;
};
struct kvaser_pciefd_dev_ops {
void (*kvaser_pciefd_write_dma_map)(struct kvaser_pciefd *pcie,
dma_addr_t addr, int index);
};
struct kvaser_pciefd_irq_mask {
u32 kcan_rx0;
u32 kcan_tx[KVASER_PCIEFD_MAX_CAN_CHANNELS];
u32 all;
};
struct kvaser_pciefd_driver_data {
const struct kvaser_pciefd_address_offset *address_offset;
const struct kvaser_pciefd_irq_mask *irq_mask;
const struct kvaser_pciefd_dev_ops *ops;
};
static const struct kvaser_pciefd_address_offset kvaser_pciefd_altera_address_offset = {
.serdes = 0x1000,
.pci_ien = 0x50,
.pci_irq = 0x40,
.sysid = 0x1f020,
.loopback = 0x1f000,
.kcan_srb_fifo = 0x1f200,
.kcan_srb = 0x1f400,
.kcan_ch0 = 0x10000,
.kcan_ch1 = 0x11000,
};
static const struct kvaser_pciefd_address_offset kvaser_pciefd_sf2_address_offset = {
.serdes = 0x280c8,
.pci_ien = 0x102004,
.pci_irq = 0x102008,
.sysid = 0x100000,
.loopback = 0x103000,
.kcan_srb_fifo = 0x120000,
.kcan_srb = 0x121000,
.kcan_ch0 = 0x140000,
.kcan_ch1 = 0x142000,
};
static const struct kvaser_pciefd_irq_mask kvaser_pciefd_altera_irq_mask = {
.kcan_rx0 = BIT(4),
.kcan_tx = { BIT(0), BIT(1), BIT(2), BIT(3) },
.all = GENMASK(4, 0),
};
static const struct kvaser_pciefd_irq_mask kvaser_pciefd_sf2_irq_mask = {
.kcan_rx0 = BIT(4),
.kcan_tx = { BIT(16), BIT(17), BIT(18), BIT(19) },
.all = GENMASK(19, 16) | BIT(4),
};
static const struct kvaser_pciefd_dev_ops kvaser_pciefd_altera_dev_ops = {
.kvaser_pciefd_write_dma_map = kvaser_pciefd_write_dma_map_altera,
};
static const struct kvaser_pciefd_dev_ops kvaser_pciefd_sf2_dev_ops = {
.kvaser_pciefd_write_dma_map = kvaser_pciefd_write_dma_map_sf2,
};
static const struct kvaser_pciefd_driver_data kvaser_pciefd_altera_driver_data = {
.address_offset = &kvaser_pciefd_altera_address_offset,
.irq_mask = &kvaser_pciefd_altera_irq_mask,
.ops = &kvaser_pciefd_altera_dev_ops,
};
static const struct kvaser_pciefd_driver_data kvaser_pciefd_sf2_driver_data = {
.address_offset = &kvaser_pciefd_sf2_address_offset,
.irq_mask = &kvaser_pciefd_sf2_irq_mask,
.ops = &kvaser_pciefd_sf2_dev_ops,
};
struct kvaser_pciefd_can { struct kvaser_pciefd_can {
struct can_priv can; struct can_priv can;
...@@ -273,6 +385,7 @@ struct kvaser_pciefd { ...@@ -273,6 +385,7 @@ struct kvaser_pciefd {
struct pci_dev *pci; struct pci_dev *pci;
void __iomem *reg_base; void __iomem *reg_base;
struct kvaser_pciefd_can *can[KVASER_PCIEFD_MAX_CAN_CHANNELS]; struct kvaser_pciefd_can *can[KVASER_PCIEFD_MAX_CAN_CHANNELS];
const struct kvaser_pciefd_driver_data *driver_data;
void *dma_data[KVASER_PCIEFD_DMA_COUNT]; void *dma_data[KVASER_PCIEFD_DMA_COUNT];
u8 nr_channels; u8 nr_channels;
u32 bus_freq; u32 bus_freq;
...@@ -305,18 +418,43 @@ static const struct can_bittiming_const kvaser_pciefd_bittiming_const = { ...@@ -305,18 +418,43 @@ static const struct can_bittiming_const kvaser_pciefd_bittiming_const = {
static struct pci_device_id kvaser_pciefd_id_table[] = { static struct pci_device_id kvaser_pciefd_id_table[] = {
{ {
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_4HS_DEVICE_ID), PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_4HS_DEVICE_ID),
.driver_data = (kernel_ulong_t)&kvaser_pciefd_altera_driver_data,
}, },
{ {
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_2HS_V2_DEVICE_ID), PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_2HS_V2_DEVICE_ID),
.driver_data = (kernel_ulong_t)&kvaser_pciefd_altera_driver_data,
}, },
{ {
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_HS_V2_DEVICE_ID), PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_HS_V2_DEVICE_ID),
.driver_data = (kernel_ulong_t)&kvaser_pciefd_altera_driver_data,
}, },
{ {
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_MINIPCIE_HS_V2_DEVICE_ID), PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_MINIPCIE_HS_V2_DEVICE_ID),
.driver_data = (kernel_ulong_t)&kvaser_pciefd_altera_driver_data,
}, },
{ {
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_MINIPCIE_2HS_V2_DEVICE_ID), PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_MINIPCIE_2HS_V2_DEVICE_ID),
.driver_data = (kernel_ulong_t)&kvaser_pciefd_altera_driver_data,
},
{
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_2CAN_V3_DEVICE_ID),
.driver_data = (kernel_ulong_t)&kvaser_pciefd_sf2_driver_data,
},
{
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_1CAN_V3_DEVICE_ID),
.driver_data = (kernel_ulong_t)&kvaser_pciefd_sf2_driver_data,
},
{
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_4CAN_V2_DEVICE_ID),
.driver_data = (kernel_ulong_t)&kvaser_pciefd_sf2_driver_data,
},
{
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_MINIPCIE_2CAN_V3_DEVICE_ID),
.driver_data = (kernel_ulong_t)&kvaser_pciefd_sf2_driver_data,
},
{
PCI_DEVICE(KVASER_PCIEFD_VENDOR, KVASER_PCIEFD_MINIPCIE_1CAN_V3_DEVICE_ID),
.driver_data = (kernel_ulong_t)&kvaser_pciefd_sf2_driver_data,
}, },
{ {
0, 0,
...@@ -783,8 +921,7 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie) ...@@ -783,8 +921,7 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie)
can = netdev_priv(netdev); can = netdev_priv(netdev);
netdev->netdev_ops = &kvaser_pciefd_netdev_ops; netdev->netdev_ops = &kvaser_pciefd_netdev_ops;
netdev->ethtool_ops = &kvaser_pciefd_ethtool_ops; netdev->ethtool_ops = &kvaser_pciefd_ethtool_ops;
can->reg_base = pcie->reg_base + KVASER_PCIEFD_KCAN0_BASE + can->reg_base = KVASER_PCIEFD_KCAN_CHX_ADDR(pcie, i);
i * KVASER_PCIEFD_KCAN_BASE_OFFSET;
can->kv_pcie = pcie; can->kv_pcie = pcie;
can->cmd_seq = 0; can->cmd_seq = 0;
can->err_rep_cnt = 0; can->err_rep_cnt = 0;
...@@ -865,20 +1002,37 @@ static int kvaser_pciefd_reg_candev(struct kvaser_pciefd *pcie) ...@@ -865,20 +1002,37 @@ static int kvaser_pciefd_reg_candev(struct kvaser_pciefd *pcie)
return 0; return 0;
} }
static void kvaser_pciefd_write_dma_map(struct kvaser_pciefd *pcie, static void kvaser_pciefd_write_dma_map_altera(struct kvaser_pciefd *pcie,
dma_addr_t addr, int offset) dma_addr_t addr, int index)
{ {
void __iomem *serdes_base;
u32 word1, word2; u32 word1, word2;
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
word1 = addr | KVASER_PCIEFD_64BIT_DMA_BIT; word1 = addr | KVASER_PCIEFD_ALTERA_DMA_64BIT;
word2 = addr >> 32; word2 = addr >> 32;
#else #else
word1 = addr; word1 = addr;
word2 = 0; word2 = 0;
#endif #endif
iowrite32(word1, pcie->reg_base + offset); serdes_base = KVASER_PCIEFD_SERDES_ADDR(pcie) + 0x8 * index;
iowrite32(word2, pcie->reg_base + offset + 4); iowrite32(word1, serdes_base);
iowrite32(word2, serdes_base + 0x4);
}
static void kvaser_pciefd_write_dma_map_sf2(struct kvaser_pciefd *pcie,
dma_addr_t addr, int index)
{
void __iomem *serdes_base;
u32 lsb = addr & KVASER_PCIEFD_SF2_DMA_LSB_MASK;
u32 msb = 0x0;
#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
msb = addr >> 32;
#endif
serdes_base = KVASER_PCIEFD_SERDES_ADDR(pcie) + 0x10 * index;
iowrite32(lsb, serdes_base);
iowrite32(msb, serdes_base + 0x4);
} }
static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie) static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie)
...@@ -889,10 +1043,8 @@ static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie) ...@@ -889,10 +1043,8 @@ static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie)
dma_addr_t dma_addr[KVASER_PCIEFD_DMA_COUNT]; dma_addr_t dma_addr[KVASER_PCIEFD_DMA_COUNT];
/* Disable the DMA */ /* Disable the DMA */
iowrite32(0, pcie->reg_base + KVASER_PCIEFD_SRB_CTRL_REG); iowrite32(0, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CTRL_REG);
for (i = 0; i < KVASER_PCIEFD_DMA_COUNT; i++) { for (i = 0; i < KVASER_PCIEFD_DMA_COUNT; i++) {
unsigned int offset = KVASER_PCIEFD_DMA_MAP_BASE + 8 * i;
pcie->dma_data[i] = dmam_alloc_coherent(&pcie->pci->dev, pcie->dma_data[i] = dmam_alloc_coherent(&pcie->pci->dev,
KVASER_PCIEFD_DMA_SIZE, KVASER_PCIEFD_DMA_SIZE,
&dma_addr[i], &dma_addr[i],
...@@ -903,24 +1055,25 @@ static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie) ...@@ -903,24 +1055,25 @@ static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie)
KVASER_PCIEFD_DMA_SIZE); KVASER_PCIEFD_DMA_SIZE);
return -ENOMEM; return -ENOMEM;
} }
kvaser_pciefd_write_dma_map(pcie, dma_addr[i], offset); pcie->driver_data->ops->kvaser_pciefd_write_dma_map(pcie, dma_addr[i], i);
} }
/* Reset Rx FIFO, and both DMA buffers */ /* Reset Rx FIFO, and both DMA buffers */
iowrite32(KVASER_PCIEFD_SRB_CMD_FOR | KVASER_PCIEFD_SRB_CMD_RDB0 | iowrite32(KVASER_PCIEFD_SRB_CMD_FOR | KVASER_PCIEFD_SRB_CMD_RDB0 |
KVASER_PCIEFD_SRB_CMD_RDB1, KVASER_PCIEFD_SRB_CMD_RDB1,
pcie->reg_base + KVASER_PCIEFD_SRB_CMD_REG); KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG);
/* Empty Rx FIFO */ /* Empty Rx FIFO */
srb_packet_count = srb_packet_count =
FIELD_GET(KVASER_PCIEFD_SRB_RX_NR_PACKETS_MASK, FIELD_GET(KVASER_PCIEFD_SRB_RX_NR_PACKETS_MASK,
ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_RX_NR_PACKETS_REG)); ioread32(KVASER_PCIEFD_SRB_ADDR(pcie) +
KVASER_PCIEFD_SRB_RX_NR_PACKETS_REG));
while (srb_packet_count) { while (srb_packet_count) {
/* Drop current packet in FIFO */ /* Drop current packet in FIFO */
ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_FIFO_LAST_REG); ioread32(KVASER_PCIEFD_SRB_FIFO_ADDR(pcie) + KVASER_PCIEFD_SRB_FIFO_LAST_REG);
srb_packet_count--; srb_packet_count--;
} }
srb_status = ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_STAT_REG); srb_status = ioread32(KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_STAT_REG);
if (!(srb_status & KVASER_PCIEFD_SRB_STAT_DI)) { if (!(srb_status & KVASER_PCIEFD_SRB_STAT_DI)) {
dev_err(&pcie->pci->dev, "DMA not idle before enabling\n"); dev_err(&pcie->pci->dev, "DMA not idle before enabling\n");
return -EIO; return -EIO;
...@@ -928,7 +1081,7 @@ static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie) ...@@ -928,7 +1081,7 @@ static int kvaser_pciefd_setup_dma(struct kvaser_pciefd *pcie)
/* Enable the DMA */ /* Enable the DMA */
iowrite32(KVASER_PCIEFD_SRB_CTRL_DMA_ENABLE, iowrite32(KVASER_PCIEFD_SRB_CTRL_DMA_ENABLE,
pcie->reg_base + KVASER_PCIEFD_SRB_CTRL_REG); KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CTRL_REG);
return 0; return 0;
} }
...@@ -937,30 +1090,29 @@ static int kvaser_pciefd_setup_board(struct kvaser_pciefd *pcie) ...@@ -937,30 +1090,29 @@ static int kvaser_pciefd_setup_board(struct kvaser_pciefd *pcie)
{ {
u32 version, srb_status, build; u32 version, srb_status, build;
version = ioread32(pcie->reg_base + KVASER_PCIEFD_SYSID_VERSION_REG); version = ioread32(KVASER_PCIEFD_SYSID_ADDR(pcie) + KVASER_PCIEFD_SYSID_VERSION_REG);
pcie->nr_channels = min(KVASER_PCIEFD_MAX_CAN_CHANNELS, pcie->nr_channels = min(KVASER_PCIEFD_MAX_CAN_CHANNELS,
FIELD_GET(KVASER_PCIEFD_SYSID_VERSION_NR_CHAN_MASK, version)); FIELD_GET(KVASER_PCIEFD_SYSID_VERSION_NR_CHAN_MASK, version));
build = ioread32(pcie->reg_base + KVASER_PCIEFD_SYSID_BUILD_REG); build = ioread32(KVASER_PCIEFD_SYSID_ADDR(pcie) + KVASER_PCIEFD_SYSID_BUILD_REG);
dev_dbg(&pcie->pci->dev, "Version %lu.%lu.%lu\n", dev_dbg(&pcie->pci->dev, "Version %lu.%lu.%lu\n",
FIELD_GET(KVASER_PCIEFD_SYSID_VERSION_MAJOR_MASK, version), FIELD_GET(KVASER_PCIEFD_SYSID_VERSION_MAJOR_MASK, version),
FIELD_GET(KVASER_PCIEFD_SYSID_VERSION_MINOR_MASK, version), FIELD_GET(KVASER_PCIEFD_SYSID_VERSION_MINOR_MASK, version),
FIELD_GET(KVASER_PCIEFD_SYSID_BUILD_SEQ_MASK, build)); FIELD_GET(KVASER_PCIEFD_SYSID_BUILD_SEQ_MASK, build));
srb_status = ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_STAT_REG); srb_status = ioread32(KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_STAT_REG);
if (!(srb_status & KVASER_PCIEFD_SRB_STAT_DMA)) { if (!(srb_status & KVASER_PCIEFD_SRB_STAT_DMA)) {
dev_err(&pcie->pci->dev, "Hardware without DMA is not supported\n"); dev_err(&pcie->pci->dev, "Hardware without DMA is not supported\n");
return -ENODEV; return -ENODEV;
} }
pcie->bus_freq = ioread32(pcie->reg_base + pcie->bus_freq = ioread32(KVASER_PCIEFD_SYSID_ADDR(pcie) + KVASER_PCIEFD_SYSID_BUSFREQ_REG);
KVASER_PCIEFD_SYSID_BUSFREQ_REG); pcie->freq = ioread32(KVASER_PCIEFD_SYSID_ADDR(pcie) + KVASER_PCIEFD_SYSID_CANFREQ_REG);
pcie->freq = ioread32(pcie->reg_base + KVASER_PCIEFD_SYSID_CANFREQ_REG);
pcie->freq_to_ticks_div = pcie->freq / 1000000; pcie->freq_to_ticks_div = pcie->freq / 1000000;
if (pcie->freq_to_ticks_div == 0) if (pcie->freq_to_ticks_div == 0)
pcie->freq_to_ticks_div = 1; pcie->freq_to_ticks_div = 1;
/* Turn off all loopback functionality */ /* Turn off all loopback functionality */
iowrite32(0, pcie->reg_base + KVASER_PCIEFD_LOOP_REG); iowrite32(0, KVASER_PCIEFD_LOOPBACK_ADDR(pcie));
return 0; return 0;
} }
...@@ -1430,21 +1582,20 @@ static int kvaser_pciefd_read_buffer(struct kvaser_pciefd *pcie, int dma_buf) ...@@ -1430,21 +1582,20 @@ static int kvaser_pciefd_read_buffer(struct kvaser_pciefd *pcie, int dma_buf)
static void kvaser_pciefd_receive_irq(struct kvaser_pciefd *pcie) static void kvaser_pciefd_receive_irq(struct kvaser_pciefd *pcie)
{ {
u32 irq; u32 irq = ioread32(KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IRQ_REG);
irq = ioread32(pcie->reg_base + KVASER_PCIEFD_SRB_IRQ_REG);
if (irq & KVASER_PCIEFD_SRB_IRQ_DPD0) { if (irq & KVASER_PCIEFD_SRB_IRQ_DPD0) {
kvaser_pciefd_read_buffer(pcie, 0); kvaser_pciefd_read_buffer(pcie, 0);
/* Reset DMA buffer 0 */ /* Reset DMA buffer 0 */
iowrite32(KVASER_PCIEFD_SRB_CMD_RDB0, iowrite32(KVASER_PCIEFD_SRB_CMD_RDB0,
pcie->reg_base + KVASER_PCIEFD_SRB_CMD_REG); KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG);
} }
if (irq & KVASER_PCIEFD_SRB_IRQ_DPD1) { if (irq & KVASER_PCIEFD_SRB_IRQ_DPD1) {
kvaser_pciefd_read_buffer(pcie, 1); kvaser_pciefd_read_buffer(pcie, 1);
/* Reset DMA buffer 1 */ /* Reset DMA buffer 1 */
iowrite32(KVASER_PCIEFD_SRB_CMD_RDB1, iowrite32(KVASER_PCIEFD_SRB_CMD_RDB1,
pcie->reg_base + KVASER_PCIEFD_SRB_CMD_REG); KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG);
} }
if (irq & KVASER_PCIEFD_SRB_IRQ_DOF0 || if (irq & KVASER_PCIEFD_SRB_IRQ_DOF0 ||
...@@ -1453,7 +1604,7 @@ static void kvaser_pciefd_receive_irq(struct kvaser_pciefd *pcie) ...@@ -1453,7 +1604,7 @@ static void kvaser_pciefd_receive_irq(struct kvaser_pciefd *pcie)
irq & KVASER_PCIEFD_SRB_IRQ_DUF1) irq & KVASER_PCIEFD_SRB_IRQ_DUF1)
dev_err(&pcie->pci->dev, "DMA IRQ error 0x%08X\n", irq); dev_err(&pcie->pci->dev, "DMA IRQ error 0x%08X\n", irq);
iowrite32(irq, pcie->reg_base + KVASER_PCIEFD_SRB_IRQ_REG); iowrite32(irq, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IRQ_REG);
} }
static void kvaser_pciefd_transmit_irq(struct kvaser_pciefd_can *can) static void kvaser_pciefd_transmit_irq(struct kvaser_pciefd_can *can)
...@@ -1479,15 +1630,14 @@ static void kvaser_pciefd_transmit_irq(struct kvaser_pciefd_can *can) ...@@ -1479,15 +1630,14 @@ static void kvaser_pciefd_transmit_irq(struct kvaser_pciefd_can *can)
static irqreturn_t kvaser_pciefd_irq_handler(int irq, void *dev) static irqreturn_t kvaser_pciefd_irq_handler(int irq, void *dev)
{ {
struct kvaser_pciefd *pcie = (struct kvaser_pciefd *)dev; struct kvaser_pciefd *pcie = (struct kvaser_pciefd *)dev;
u32 board_irq; const struct kvaser_pciefd_irq_mask *irq_mask = pcie->driver_data->irq_mask;
u32 board_irq = ioread32(KVASER_PCIEFD_PCI_IRQ_ADDR(pcie));
int i; int i;
board_irq = ioread32(pcie->reg_base + KVASER_PCIEFD_IRQ_REG); if (!(board_irq & irq_mask->all))
if (!(board_irq & KVASER_PCIEFD_IRQ_ALL_MASK))
return IRQ_NONE; return IRQ_NONE;
if (board_irq & KVASER_PCIEFD_IRQ_SRB) if (board_irq & irq_mask->kcan_rx0)
kvaser_pciefd_receive_irq(pcie); kvaser_pciefd_receive_irq(pcie);
for (i = 0; i < pcie->nr_channels; i++) { for (i = 0; i < pcie->nr_channels; i++) {
...@@ -1498,7 +1648,7 @@ static irqreturn_t kvaser_pciefd_irq_handler(int irq, void *dev) ...@@ -1498,7 +1648,7 @@ static irqreturn_t kvaser_pciefd_irq_handler(int irq, void *dev)
} }
/* Check that mask matches channel (i) IRQ mask */ /* Check that mask matches channel (i) IRQ mask */
if (board_irq & (1 << i)) if (board_irq & irq_mask->kcan_tx[i])
kvaser_pciefd_transmit_irq(pcie->can[i]); kvaser_pciefd_transmit_irq(pcie->can[i]);
} }
...@@ -1525,6 +1675,8 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev, ...@@ -1525,6 +1675,8 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev,
{ {
int err; int err;
struct kvaser_pciefd *pcie; struct kvaser_pciefd *pcie;
const struct kvaser_pciefd_irq_mask *irq_mask;
void __iomem *irq_en_base;
pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL); pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
if (!pcie) if (!pcie)
...@@ -1532,6 +1684,8 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev, ...@@ -1532,6 +1684,8 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, pcie); pci_set_drvdata(pdev, pcie);
pcie->pci = pdev; pcie->pci = pdev;
pcie->driver_data = (const struct kvaser_pciefd_driver_data *)id->driver_data;
irq_mask = pcie->driver_data->irq_mask;
err = pci_enable_device(pdev); err = pci_enable_device(pdev);
if (err) if (err)
...@@ -1567,22 +1721,21 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev, ...@@ -1567,22 +1721,21 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev,
goto err_teardown_can_ctrls; goto err_teardown_can_ctrls;
iowrite32(KVASER_PCIEFD_SRB_IRQ_DPD0 | KVASER_PCIEFD_SRB_IRQ_DPD1, iowrite32(KVASER_PCIEFD_SRB_IRQ_DPD0 | KVASER_PCIEFD_SRB_IRQ_DPD1,
pcie->reg_base + KVASER_PCIEFD_SRB_IRQ_REG); KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IRQ_REG);
iowrite32(KVASER_PCIEFD_SRB_IRQ_DPD0 | KVASER_PCIEFD_SRB_IRQ_DPD1 | iowrite32(KVASER_PCIEFD_SRB_IRQ_DPD0 | KVASER_PCIEFD_SRB_IRQ_DPD1 |
KVASER_PCIEFD_SRB_IRQ_DOF0 | KVASER_PCIEFD_SRB_IRQ_DOF1 | KVASER_PCIEFD_SRB_IRQ_DOF0 | KVASER_PCIEFD_SRB_IRQ_DOF1 |
KVASER_PCIEFD_SRB_IRQ_DUF0 | KVASER_PCIEFD_SRB_IRQ_DUF1, KVASER_PCIEFD_SRB_IRQ_DUF0 | KVASER_PCIEFD_SRB_IRQ_DUF1,
pcie->reg_base + KVASER_PCIEFD_SRB_IEN_REG); KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_IEN_REG);
/* Enable PCI interrupts */ /* Enable PCI interrupts */
iowrite32(KVASER_PCIEFD_IRQ_ALL_MASK, irq_en_base = KVASER_PCIEFD_PCI_IEN_ADDR(pcie);
pcie->reg_base + KVASER_PCIEFD_IEN_REG); iowrite32(irq_mask->all, irq_en_base);
/* Ready the DMA buffers */ /* Ready the DMA buffers */
iowrite32(KVASER_PCIEFD_SRB_CMD_RDB0, iowrite32(KVASER_PCIEFD_SRB_CMD_RDB0,
pcie->reg_base + KVASER_PCIEFD_SRB_CMD_REG); KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG);
iowrite32(KVASER_PCIEFD_SRB_CMD_RDB1, iowrite32(KVASER_PCIEFD_SRB_CMD_RDB1,
pcie->reg_base + KVASER_PCIEFD_SRB_CMD_REG); KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CMD_REG);
err = kvaser_pciefd_reg_candev(pcie); err = kvaser_pciefd_reg_candev(pcie);
if (err) if (err)
...@@ -1592,12 +1745,12 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev, ...@@ -1592,12 +1745,12 @@ static int kvaser_pciefd_probe(struct pci_dev *pdev,
err_free_irq: err_free_irq:
/* Disable PCI interrupts */ /* Disable PCI interrupts */
iowrite32(0, pcie->reg_base + KVASER_PCIEFD_IEN_REG); iowrite32(0, irq_en_base);
free_irq(pcie->pci->irq, pcie); free_irq(pcie->pci->irq, pcie);
err_teardown_can_ctrls: err_teardown_can_ctrls:
kvaser_pciefd_teardown_can_ctrls(pcie); kvaser_pciefd_teardown_can_ctrls(pcie);
iowrite32(0, pcie->reg_base + KVASER_PCIEFD_SRB_CTRL_REG); iowrite32(0, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CTRL_REG);
pci_clear_master(pdev); pci_clear_master(pdev);
err_pci_iounmap: err_pci_iounmap:
...@@ -1636,8 +1789,8 @@ static void kvaser_pciefd_remove(struct pci_dev *pdev) ...@@ -1636,8 +1789,8 @@ static void kvaser_pciefd_remove(struct pci_dev *pdev)
kvaser_pciefd_remove_all_ctrls(pcie); kvaser_pciefd_remove_all_ctrls(pcie);
/* Disable interrupts */ /* Disable interrupts */
iowrite32(0, pcie->reg_base + KVASER_PCIEFD_SRB_CTRL_REG); iowrite32(0, KVASER_PCIEFD_SRB_ADDR(pcie) + KVASER_PCIEFD_SRB_CTRL_REG);
iowrite32(0, pcie->reg_base + KVASER_PCIEFD_IEN_REG); iowrite32(0, KVASER_PCIEFD_PCI_IEN_ADDR(pcie));
free_irq(pcie->pci->irq, pcie); free_irq(pcie->pci->irq, pcie);
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/bitfield.h> #include <linux/bitfield.h>
#include <linux/can/dev.h> #include <linux/can/dev.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/hrtimer.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
...@@ -308,6 +309,9 @@ enum m_can_reg { ...@@ -308,6 +309,9 @@ enum m_can_reg {
#define TX_EVENT_MM_MASK GENMASK(31, 24) #define TX_EVENT_MM_MASK GENMASK(31, 24)
#define TX_EVENT_TXTS_MASK GENMASK(15, 0) #define TX_EVENT_TXTS_MASK GENMASK(15, 0)
/* Hrtimer polling interval */
#define HRTIMER_POLL_INTERVAL_MS 1
/* The ID and DLC registers are adjacent in M_CAN FIFO memory, /* The ID and DLC registers are adjacent in M_CAN FIFO memory,
* and we can save a (potentially slow) bus round trip by combining * and we can save a (potentially slow) bus round trip by combining
* reads and writes to them. * reads and writes to them.
...@@ -1414,6 +1418,12 @@ static int m_can_start(struct net_device *dev) ...@@ -1414,6 +1418,12 @@ static int m_can_start(struct net_device *dev)
m_can_enable_all_interrupts(cdev); m_can_enable_all_interrupts(cdev);
if (!dev->irq) {
dev_dbg(cdev->dev, "Start hrtimer\n");
hrtimer_start(&cdev->hrtimer, ms_to_ktime(HRTIMER_POLL_INTERVAL_MS),
HRTIMER_MODE_REL_PINNED);
}
return 0; return 0;
} }
...@@ -1568,6 +1578,11 @@ static void m_can_stop(struct net_device *dev) ...@@ -1568,6 +1578,11 @@ static void m_can_stop(struct net_device *dev)
{ {
struct m_can_classdev *cdev = netdev_priv(dev); struct m_can_classdev *cdev = netdev_priv(dev);
if (!dev->irq) {
dev_dbg(cdev->dev, "Stop hrtimer\n");
hrtimer_cancel(&cdev->hrtimer);
}
/* disable all interrupts */ /* disable all interrupts */
m_can_disable_all_interrupts(cdev); m_can_disable_all_interrupts(cdev);
...@@ -1793,6 +1808,18 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb, ...@@ -1793,6 +1808,18 @@ static netdev_tx_t m_can_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
static enum hrtimer_restart hrtimer_callback(struct hrtimer *timer)
{
struct m_can_classdev *cdev = container_of(timer, struct
m_can_classdev, hrtimer);
m_can_isr(0, cdev->net);
hrtimer_forward_now(timer, ms_to_ktime(HRTIMER_POLL_INTERVAL_MS));
return HRTIMER_RESTART;
}
static int m_can_open(struct net_device *dev) static int m_can_open(struct net_device *dev)
{ {
struct m_can_classdev *cdev = netdev_priv(dev); struct m_can_classdev *cdev = netdev_priv(dev);
...@@ -1831,7 +1858,7 @@ static int m_can_open(struct net_device *dev) ...@@ -1831,7 +1858,7 @@ static int m_can_open(struct net_device *dev)
err = request_threaded_irq(dev->irq, NULL, m_can_isr, err = request_threaded_irq(dev->irq, NULL, m_can_isr,
IRQF_ONESHOT, IRQF_ONESHOT,
dev->name, dev); dev->name, dev);
} else { } else if (dev->irq) {
err = request_irq(dev->irq, m_can_isr, IRQF_SHARED, dev->name, err = request_irq(dev->irq, m_can_isr, IRQF_SHARED, dev->name,
dev); dev);
} }
...@@ -2027,6 +2054,9 @@ int m_can_class_register(struct m_can_classdev *cdev) ...@@ -2027,6 +2054,9 @@ int m_can_class_register(struct m_can_classdev *cdev)
goto clk_disable; goto clk_disable;
} }
if (!cdev->net->irq)
cdev->hrtimer.function = &hrtimer_callback;
ret = m_can_dev_setup(cdev); ret = m_can_dev_setup(cdev);
if (ret) if (ret)
goto rx_offload_del; goto rx_offload_del;
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/device.h> #include <linux/device.h>
#include <linux/dma-mapping.h> #include <linux/dma-mapping.h>
#include <linux/freezer.h> #include <linux/freezer.h>
#include <linux/hrtimer.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/io.h> #include <linux/io.h>
#include <linux/iopoll.h> #include <linux/iopoll.h>
...@@ -93,6 +94,8 @@ struct m_can_classdev { ...@@ -93,6 +94,8 @@ struct m_can_classdev {
int is_peripheral; int is_peripheral;
struct mram_cfg mcfg[MRAM_CFG_NUM]; struct mram_cfg mcfg[MRAM_CFG_NUM];
struct hrtimer hrtimer;
}; };
struct m_can_classdev *m_can_class_allocate_dev(struct device *dev, int sizeof_priv); struct m_can_classdev *m_can_class_allocate_dev(struct device *dev, int sizeof_priv);
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
// //
// Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/ // Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/
#include <linux/hrtimer.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
...@@ -82,7 +83,7 @@ static int m_can_plat_probe(struct platform_device *pdev) ...@@ -82,7 +83,7 @@ static int m_can_plat_probe(struct platform_device *pdev)
void __iomem *addr; void __iomem *addr;
void __iomem *mram_addr; void __iomem *mram_addr;
struct phy *transceiver; struct phy *transceiver;
int irq, ret = 0; int irq = 0, ret = 0;
mcan_class = m_can_class_allocate_dev(&pdev->dev, mcan_class = m_can_class_allocate_dev(&pdev->dev,
sizeof(struct m_can_plat_priv)); sizeof(struct m_can_plat_priv));
...@@ -96,12 +97,24 @@ static int m_can_plat_probe(struct platform_device *pdev) ...@@ -96,12 +97,24 @@ static int m_can_plat_probe(struct platform_device *pdev)
goto probe_fail; goto probe_fail;
addr = devm_platform_ioremap_resource_byname(pdev, "m_can"); addr = devm_platform_ioremap_resource_byname(pdev, "m_can");
irq = platform_get_irq_byname(pdev, "int0"); if (IS_ERR(addr)) {
if (IS_ERR(addr) || irq < 0) { ret = PTR_ERR(addr);
ret = -EINVAL;
goto probe_fail; goto probe_fail;
} }
if (device_property_present(mcan_class->dev, "interrupts") ||
device_property_present(mcan_class->dev, "interrupt-names")) {
irq = platform_get_irq_byname(pdev, "int0");
if (irq < 0) {
ret = irq;
goto probe_fail;
}
} else {
dev_dbg(mcan_class->dev, "Polling enabled, initialize hrtimer");
hrtimer_init(&mcan_class->hrtimer, CLOCK_MONOTONIC,
HRTIMER_MODE_REL_PINNED);
}
/* message ram could be shared */ /* message ram could be shared */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "message_ram"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "message_ram");
if (!res) { if (!res) {
......
...@@ -284,7 +284,7 @@ struct ucan_priv { ...@@ -284,7 +284,7 @@ struct ucan_priv {
*/ */
spinlock_t echo_skb_lock; spinlock_t echo_skb_lock;
/* usb device information information */ /* usb device information */
u8 intf_index; u8 intf_index;
u8 in_ep_addr; u8 in_ep_addr;
u8 out_ep_addr; u8 out_ep_addr;
......
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/can/error.h> #include <linux/can/error.h>
#include <linux/phy/phy.h> #include <linux/phy/phy.h>
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <linux/reset.h>
#define DRIVER_NAME "xilinx_can" #define DRIVER_NAME "xilinx_can"
...@@ -200,6 +201,7 @@ struct xcan_devtype_data { ...@@ -200,6 +201,7 @@ struct xcan_devtype_data {
* @can_clk: Pointer to struct clk * @can_clk: Pointer to struct clk
* @devtype: Device type specific constants * @devtype: Device type specific constants
* @transceiver: Optional pointer to associated CAN transceiver * @transceiver: Optional pointer to associated CAN transceiver
* @rstc: Pointer to reset control
*/ */
struct xcan_priv { struct xcan_priv {
struct can_priv can; struct can_priv can;
...@@ -218,6 +220,7 @@ struct xcan_priv { ...@@ -218,6 +220,7 @@ struct xcan_priv {
struct clk *can_clk; struct clk *can_clk;
struct xcan_devtype_data devtype; struct xcan_devtype_data devtype;
struct phy *transceiver; struct phy *transceiver;
struct reset_control *rstc;
}; };
/* CAN Bittiming constants as per Xilinx CAN specs */ /* CAN Bittiming constants as per Xilinx CAN specs */
...@@ -1799,6 +1802,16 @@ static int xcan_probe(struct platform_device *pdev) ...@@ -1799,6 +1802,16 @@ static int xcan_probe(struct platform_device *pdev)
priv->can.do_get_berr_counter = xcan_get_berr_counter; priv->can.do_get_berr_counter = xcan_get_berr_counter;
priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK | priv->can.ctrlmode_supported = CAN_CTRLMODE_LOOPBACK |
CAN_CTRLMODE_BERR_REPORTING; CAN_CTRLMODE_BERR_REPORTING;
priv->rstc = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL);
if (IS_ERR(priv->rstc)) {
dev_err(&pdev->dev, "Cannot get CAN reset.\n");
ret = PTR_ERR(priv->rstc);
goto err_free;
}
ret = reset_control_reset(priv->rstc);
if (ret)
goto err_free;
if (devtype->cantype == XAXI_CANFD) { if (devtype->cantype == XAXI_CANFD) {
priv->can.data_bittiming_const = priv->can.data_bittiming_const =
...@@ -1827,7 +1840,7 @@ static int xcan_probe(struct platform_device *pdev) ...@@ -1827,7 +1840,7 @@ static int xcan_probe(struct platform_device *pdev)
/* Get IRQ for the device */ /* Get IRQ for the device */
ret = platform_get_irq(pdev, 0); ret = platform_get_irq(pdev, 0);
if (ret < 0) if (ret < 0)
goto err_free; goto err_reset;
ndev->irq = ret; ndev->irq = ret;
...@@ -1843,21 +1856,21 @@ static int xcan_probe(struct platform_device *pdev) ...@@ -1843,21 +1856,21 @@ static int xcan_probe(struct platform_device *pdev)
if (IS_ERR(priv->can_clk)) { if (IS_ERR(priv->can_clk)) {
ret = dev_err_probe(&pdev->dev, PTR_ERR(priv->can_clk), ret = dev_err_probe(&pdev->dev, PTR_ERR(priv->can_clk),
"device clock not found\n"); "device clock not found\n");
goto err_free; goto err_reset;
} }
priv->bus_clk = devm_clk_get(&pdev->dev, devtype->bus_clk_name); priv->bus_clk = devm_clk_get(&pdev->dev, devtype->bus_clk_name);
if (IS_ERR(priv->bus_clk)) { if (IS_ERR(priv->bus_clk)) {
ret = dev_err_probe(&pdev->dev, PTR_ERR(priv->bus_clk), ret = dev_err_probe(&pdev->dev, PTR_ERR(priv->bus_clk),
"bus clock not found\n"); "bus clock not found\n");
goto err_free; goto err_reset;
} }
transceiver = devm_phy_optional_get(&pdev->dev, NULL); transceiver = devm_phy_optional_get(&pdev->dev, NULL);
if (IS_ERR(transceiver)) { if (IS_ERR(transceiver)) {
ret = PTR_ERR(transceiver); ret = PTR_ERR(transceiver);
dev_err_probe(&pdev->dev, ret, "failed to get phy\n"); dev_err_probe(&pdev->dev, ret, "failed to get phy\n");
goto err_free; goto err_reset;
} }
priv->transceiver = transceiver; priv->transceiver = transceiver;
...@@ -1904,6 +1917,8 @@ static int xcan_probe(struct platform_device *pdev) ...@@ -1904,6 +1917,8 @@ static int xcan_probe(struct platform_device *pdev)
err_disableclks: err_disableclks:
pm_runtime_put(priv->dev); pm_runtime_put(priv->dev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
err_reset:
reset_control_assert(priv->rstc);
err_free: err_free:
free_candev(ndev); free_candev(ndev);
err: err:
...@@ -1920,9 +1935,11 @@ static int xcan_probe(struct platform_device *pdev) ...@@ -1920,9 +1935,11 @@ static int xcan_probe(struct platform_device *pdev)
static void xcan_remove(struct platform_device *pdev) static void xcan_remove(struct platform_device *pdev)
{ {
struct net_device *ndev = platform_get_drvdata(pdev); struct net_device *ndev = platform_get_drvdata(pdev);
struct xcan_priv *priv = netdev_priv(ndev);
unregister_candev(ndev); unregister_candev(ndev);
pm_runtime_disable(&pdev->dev); pm_runtime_disable(&pdev->dev);
reset_control_assert(priv->rstc);
free_candev(ndev); free_candev(ndev);
} }
......
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