linux-can-next-for-5.15-20210725
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEK3kIWJt9yTYMP3ehqclaivrt76kFAmD9M0sTHG1rbEBwZW5n dXRyb25peC5kZQAKCRCpyVqK+u3vqT6SB/9S0h403FVv8IMCX2Vs3lD1ydQag8Uu B7Pnb2eI5lQ7sRyaCTBxQvZIwcClx1DKdRDqeyvHQ3GqMA9mhysyovhFfXt6OmaD VyPIOBxquothlelZwMz743dXAta8WVyMHxIQkn4PJuEHoaFRLXI1TcXtlN/rPfSr VRt/QTN8Z4xYVx34YNQcK0jxkgVkkWY0Bv0hjHO0+XIW27zeX6JeAsJZZxQAQpmx bT4pZq9oKYSq9WTIdh8uq2HeBIbcA8wlVHV7ixdVfe0hWrBW5INfB5hsQ+THjJ51 7XhO3cVaOuQZnZEta69RSFBvZiugevZXN1AJudgle16+317LTVUZ/bTX =/GFB -----END PGP SIGNATURE----- Merge tag 'linux-can-next-for-5.15-20210725' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next linux-can-next-for-5.15-20210725 Marc Kleine-Budde says: ==================== pull-request: can-next 2021-07-25 this is a pull request of 46 patches for net-next/master. The first 6 patches target the CAN J1939 protocol. One is from gushengxian, fixing a grammatical error, 5 are by me fixing a checkpatch warning, make use of the fallthrough pseudo-keyword, and use consistent variable naming. The next 3 patches target the rx-offload helper, are by me and improve the performance and fix the local softirq work pending error, when napi_schedule() is called from threaded IRQ context. The next 3 patches are by Vincent Mailhol and me update the CAN bittiming and transmitter delay compensation, the documentation for the struct can_tdc is fixed, clear data_bittiming if FD mode is turned off and a redundant check is removed. Followed by 4 patches targeting the m_can driver. Faiz Abbas's patches add support for CAN PHY via the generic phy subsystem. Yang Yingliang converts the driver to use devm_platform_ioremap_resource_byname(). And a patch by me which removes the unused support for custom bit timing. Andy Shevchenko contributes 2 patches for the mcp251xfd driver to prepare the driver for ACPI support. A patch by me adds support for shared IRQ handlers. Zhen Lei contributes 3 patches to convert the esd_usb2, janz-ican3 and the at91_can driver to make use of the DEVICE_ATTR_RO/RW() macros. The next 8 patches are by Peng Li and provide general cleanups for the at91_can driver. The next 7 patches target the peak driver. Frist 2 cleanup patches by me for the peak_pci driver, followed by Stephane Grosjean' patch to print the name and firmware version of the detected hardware. The peak_usb driver gets a cleanup patch, loopback and one-shot mode and an upgrading of the bus state change handling in Stephane Grosjean's patches. Vincent Mailhol provides 6 cleanup patches for the etas_es58x driver. In the last 3 patches Angelo Dureghello add support for the mcf5441x SoC to the flexcan driver. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
d20e5880fe
@ -107,6 +107,9 @@ properties:
|
||||
can-transceiver:
|
||||
$ref: can-transceiver.yaml#
|
||||
|
||||
phys:
|
||||
maxItems: 1
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
|
@ -97,7 +97,8 @@ config CAN_AT91
|
||||
|
||||
config CAN_FLEXCAN
|
||||
tristate "Support for Freescale FLEXCAN based chips"
|
||||
depends on OF && HAS_IOMEM
|
||||
depends on OF || COLDFIRE || COMPILE_TEST
|
||||
depends on HAS_IOMEM
|
||||
help
|
||||
Say Y here if you want to support for Freescale FlexCAN.
|
||||
|
||||
|
@ -43,14 +43,14 @@ enum at91_reg {
|
||||
};
|
||||
|
||||
/* Mailbox registers (0 <= i <= 15) */
|
||||
#define AT91_MMR(i) (enum at91_reg)(0x200 + ((i) * 0x20))
|
||||
#define AT91_MAM(i) (enum at91_reg)(0x204 + ((i) * 0x20))
|
||||
#define AT91_MID(i) (enum at91_reg)(0x208 + ((i) * 0x20))
|
||||
#define AT91_MFID(i) (enum at91_reg)(0x20C + ((i) * 0x20))
|
||||
#define AT91_MSR(i) (enum at91_reg)(0x210 + ((i) * 0x20))
|
||||
#define AT91_MDL(i) (enum at91_reg)(0x214 + ((i) * 0x20))
|
||||
#define AT91_MDH(i) (enum at91_reg)(0x218 + ((i) * 0x20))
|
||||
#define AT91_MCR(i) (enum at91_reg)(0x21C + ((i) * 0x20))
|
||||
#define AT91_MMR(i) ((enum at91_reg)(0x200 + ((i) * 0x20)))
|
||||
#define AT91_MAM(i) ((enum at91_reg)(0x204 + ((i) * 0x20)))
|
||||
#define AT91_MID(i) ((enum at91_reg)(0x208 + ((i) * 0x20)))
|
||||
#define AT91_MFID(i) ((enum at91_reg)(0x20C + ((i) * 0x20)))
|
||||
#define AT91_MSR(i) ((enum at91_reg)(0x210 + ((i) * 0x20)))
|
||||
#define AT91_MDL(i) ((enum at91_reg)(0x214 + ((i) * 0x20)))
|
||||
#define AT91_MDH(i) ((enum at91_reg)(0x218 + ((i) * 0x20)))
|
||||
#define AT91_MCR(i) ((enum at91_reg)(0x21C + ((i) * 0x20)))
|
||||
|
||||
/* Register bits */
|
||||
#define AT91_MR_CANEN BIT(0)
|
||||
@ -87,19 +87,19 @@ enum at91_mb_mode {
|
||||
};
|
||||
|
||||
/* Interrupt mask bits */
|
||||
#define AT91_IRQ_ERRA (1 << 16)
|
||||
#define AT91_IRQ_WARN (1 << 17)
|
||||
#define AT91_IRQ_ERRP (1 << 18)
|
||||
#define AT91_IRQ_BOFF (1 << 19)
|
||||
#define AT91_IRQ_SLEEP (1 << 20)
|
||||
#define AT91_IRQ_WAKEUP (1 << 21)
|
||||
#define AT91_IRQ_TOVF (1 << 22)
|
||||
#define AT91_IRQ_TSTP (1 << 23)
|
||||
#define AT91_IRQ_CERR (1 << 24)
|
||||
#define AT91_IRQ_SERR (1 << 25)
|
||||
#define AT91_IRQ_AERR (1 << 26)
|
||||
#define AT91_IRQ_FERR (1 << 27)
|
||||
#define AT91_IRQ_BERR (1 << 28)
|
||||
#define AT91_IRQ_ERRA BIT(16)
|
||||
#define AT91_IRQ_WARN BIT(17)
|
||||
#define AT91_IRQ_ERRP BIT(18)
|
||||
#define AT91_IRQ_BOFF BIT(19)
|
||||
#define AT91_IRQ_SLEEP BIT(20)
|
||||
#define AT91_IRQ_WAKEUP BIT(21)
|
||||
#define AT91_IRQ_TOVF BIT(22)
|
||||
#define AT91_IRQ_TSTP BIT(23)
|
||||
#define AT91_IRQ_CERR BIT(24)
|
||||
#define AT91_IRQ_SERR BIT(25)
|
||||
#define AT91_IRQ_AERR BIT(26)
|
||||
#define AT91_IRQ_FERR BIT(27)
|
||||
#define AT91_IRQ_BERR BIT(28)
|
||||
|
||||
#define AT91_IRQ_ERR_ALL (0x1fff0000)
|
||||
#define AT91_IRQ_ERR_FRAME (AT91_IRQ_CERR | AT91_IRQ_SERR | \
|
||||
@ -163,7 +163,7 @@ static const struct can_bittiming_const at91_bittiming_const = {
|
||||
.tseg2_min = 2,
|
||||
.tseg2_max = 8,
|
||||
.sjw_max = 4,
|
||||
.brp_min = 2,
|
||||
.brp_min = 2,
|
||||
.brp_max = 128,
|
||||
.brp_inc = 1,
|
||||
};
|
||||
@ -281,19 +281,20 @@ static inline u32 at91_read(const struct at91_priv *priv, enum at91_reg reg)
|
||||
}
|
||||
|
||||
static inline void at91_write(const struct at91_priv *priv, enum at91_reg reg,
|
||||
u32 value)
|
||||
u32 value)
|
||||
{
|
||||
writel_relaxed(value, priv->reg_base + reg);
|
||||
}
|
||||
|
||||
static inline void set_mb_mode_prio(const struct at91_priv *priv,
|
||||
unsigned int mb, enum at91_mb_mode mode, int prio)
|
||||
unsigned int mb, enum at91_mb_mode mode,
|
||||
int prio)
|
||||
{
|
||||
at91_write(priv, AT91_MMR(mb), (mode << 24) | (prio << 16));
|
||||
}
|
||||
|
||||
static inline void set_mb_mode(const struct at91_priv *priv, unsigned int mb,
|
||||
enum at91_mb_mode mode)
|
||||
enum at91_mb_mode mode)
|
||||
{
|
||||
set_mb_mode_prio(priv, mb, mode, 0);
|
||||
}
|
||||
@ -316,8 +317,7 @@ static void at91_setup_mailboxes(struct net_device *dev)
|
||||
unsigned int i;
|
||||
u32 reg_mid;
|
||||
|
||||
/*
|
||||
* Due to a chip bug (errata 50.2.6.3 & 50.3.5.3) the first
|
||||
/* Due to a chip bug (errata 50.2.6.3 & 50.3.5.3) the first
|
||||
* mailbox is disabled. The next 11 mailboxes are used as a
|
||||
* reception FIFO. The last mailbox is configured with
|
||||
* overwrite option. The overwrite flag indicates a FIFO
|
||||
@ -368,7 +368,7 @@ static int at91_set_bittiming(struct net_device *dev)
|
||||
}
|
||||
|
||||
static int at91_get_berr_counter(const struct net_device *dev,
|
||||
struct can_berr_counter *bec)
|
||||
struct can_berr_counter *bec)
|
||||
{
|
||||
const struct at91_priv *priv = netdev_priv(dev);
|
||||
u32 reg_ecr = at91_read(priv, AT91_ECR);
|
||||
@ -423,8 +423,7 @@ static void at91_chip_stop(struct net_device *dev, enum can_state state)
|
||||
priv->can.state = state;
|
||||
}
|
||||
|
||||
/*
|
||||
* theory of operation:
|
||||
/* theory of operation:
|
||||
*
|
||||
* According to the datasheet priority 0 is the highest priority, 15
|
||||
* is the lowest. If two mailboxes have the same priority level the
|
||||
@ -486,8 +485,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
/* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */
|
||||
can_put_echo_skb(skb, dev, mb - get_mb_tx_first(priv), 0);
|
||||
|
||||
/*
|
||||
* we have to stop the queue and deliver all messages in case
|
||||
/* we have to stop the queue and deliver all messages in case
|
||||
* of a prio+mb counter wrap around. This is the case if
|
||||
* tx_next buffer prio and mailbox equals 0.
|
||||
*
|
||||
@ -515,6 +513,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
static inline void at91_activate_rx_low(const struct at91_priv *priv)
|
||||
{
|
||||
u32 mask = get_mb_rx_low_mask(priv);
|
||||
|
||||
at91_write(priv, AT91_TCR, mask);
|
||||
}
|
||||
|
||||
@ -526,9 +525,10 @@ static inline void at91_activate_rx_low(const struct at91_priv *priv)
|
||||
* Reenables given mailbox for reception of new CAN messages
|
||||
*/
|
||||
static inline void at91_activate_rx_mb(const struct at91_priv *priv,
|
||||
unsigned int mb)
|
||||
unsigned int mb)
|
||||
{
|
||||
u32 mask = 1 << mb;
|
||||
|
||||
at91_write(priv, AT91_TCR, mask);
|
||||
}
|
||||
|
||||
@ -568,7 +568,7 @@ static void at91_rx_overflow_err(struct net_device *dev)
|
||||
* given can frame. "mb" and "cf" must be valid.
|
||||
*/
|
||||
static void at91_read_mb(struct net_device *dev, unsigned int mb,
|
||||
struct can_frame *cf)
|
||||
struct can_frame *cf)
|
||||
{
|
||||
const struct at91_priv *priv = netdev_priv(dev);
|
||||
u32 reg_msr, reg_mid;
|
||||
@ -582,9 +582,9 @@ static void at91_read_mb(struct net_device *dev, unsigned int mb,
|
||||
reg_msr = at91_read(priv, AT91_MSR(mb));
|
||||
cf->len = can_cc_dlc2len((reg_msr >> 16) & 0xf);
|
||||
|
||||
if (reg_msr & AT91_MSR_MRTR)
|
||||
if (reg_msr & AT91_MSR_MRTR) {
|
||||
cf->can_id |= CAN_RTR_FLAG;
|
||||
else {
|
||||
} else {
|
||||
*(u32 *)(cf->data + 0) = at91_read(priv, AT91_MDL(mb));
|
||||
*(u32 *)(cf->data + 4) = at91_read(priv, AT91_MDH(mb));
|
||||
}
|
||||
@ -685,7 +685,7 @@ static int at91_poll_rx(struct net_device *dev, int quota)
|
||||
if (priv->rx_next > get_mb_rx_low_last(priv) &&
|
||||
reg_sr & get_mb_rx_low_mask(priv))
|
||||
netdev_info(dev,
|
||||
"order of incoming frames cannot be guaranteed\n");
|
||||
"order of incoming frames cannot be guaranteed\n");
|
||||
|
||||
again:
|
||||
for (mb = find_next_bit(addr, get_mb_tx_first(priv), priv->rx_next);
|
||||
@ -718,7 +718,7 @@ static int at91_poll_rx(struct net_device *dev, int quota)
|
||||
}
|
||||
|
||||
static void at91_poll_err_frame(struct net_device *dev,
|
||||
struct can_frame *cf, u32 reg_sr)
|
||||
struct can_frame *cf, u32 reg_sr)
|
||||
{
|
||||
struct at91_priv *priv = netdev_priv(dev);
|
||||
|
||||
@ -796,8 +796,7 @@ static int at91_poll(struct napi_struct *napi, int quota)
|
||||
if (reg_sr & get_irq_mb_rx(priv))
|
||||
work_done += at91_poll_rx(dev, quota - work_done);
|
||||
|
||||
/*
|
||||
* The error bits are clear on read,
|
||||
/* The error bits are clear on read,
|
||||
* so use saved value from irq handler.
|
||||
*/
|
||||
reg_sr |= priv->reg_sr;
|
||||
@ -807,6 +806,7 @@ static int at91_poll(struct napi_struct *napi, int quota)
|
||||
if (work_done < quota) {
|
||||
/* enable IRQs for frame errors and all mailboxes >= rx_next */
|
||||
u32 reg_ier = AT91_IRQ_ERR_FRAME;
|
||||
|
||||
reg_ier |= get_irq_mb_rx(priv) & ~AT91_MB_MASK(priv->rx_next);
|
||||
|
||||
napi_complete_done(napi, work_done);
|
||||
@ -816,8 +816,7 @@ static int at91_poll(struct napi_struct *napi, int quota)
|
||||
return work_done;
|
||||
}
|
||||
|
||||
/*
|
||||
* theory of operation:
|
||||
/* theory of operation:
|
||||
*
|
||||
* priv->tx_echo holds the number of the oldest can_frame put for
|
||||
* transmission into the hardware, but not yet ACKed by the CAN tx
|
||||
@ -846,8 +845,7 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr)
|
||||
/* Disable irq for this TX mailbox */
|
||||
at91_write(priv, AT91_IDR, 1 << mb);
|
||||
|
||||
/*
|
||||
* only echo if mailbox signals us a transfer
|
||||
/* only echo if mailbox signals us a transfer
|
||||
* complete (MSR_MRDY). Otherwise it's a tansfer
|
||||
* abort. "can_bus_off()" takes care about the skbs
|
||||
* parked in the echo queue.
|
||||
@ -862,8 +860,7 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* restart queue if we don't have a wrap around but restart if
|
||||
/* restart queue if we don't have a wrap around but restart if
|
||||
* we get a TX int for the last can frame directly before a
|
||||
* wrap around.
|
||||
*/
|
||||
@ -873,7 +870,7 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr)
|
||||
}
|
||||
|
||||
static void at91_irq_err_state(struct net_device *dev,
|
||||
struct can_frame *cf, enum can_state new_state)
|
||||
struct can_frame *cf, enum can_state new_state)
|
||||
{
|
||||
struct at91_priv *priv = netdev_priv(dev);
|
||||
u32 reg_idr = 0, reg_ier = 0;
|
||||
@ -883,8 +880,7 @@ static void at91_irq_err_state(struct net_device *dev,
|
||||
|
||||
switch (priv->can.state) {
|
||||
case CAN_STATE_ERROR_ACTIVE:
|
||||
/*
|
||||
* from: ERROR_ACTIVE
|
||||
/* from: ERROR_ACTIVE
|
||||
* to : ERROR_WARNING, ERROR_PASSIVE, BUS_OFF
|
||||
* => : there was a warning int
|
||||
*/
|
||||
@ -900,8 +896,7 @@ static void at91_irq_err_state(struct net_device *dev,
|
||||
}
|
||||
fallthrough;
|
||||
case CAN_STATE_ERROR_WARNING:
|
||||
/*
|
||||
* from: ERROR_ACTIVE, ERROR_WARNING
|
||||
/* from: ERROR_ACTIVE, ERROR_WARNING
|
||||
* to : ERROR_PASSIVE, BUS_OFF
|
||||
* => : error passive int
|
||||
*/
|
||||
@ -917,8 +912,7 @@ static void at91_irq_err_state(struct net_device *dev,
|
||||
}
|
||||
break;
|
||||
case CAN_STATE_BUS_OFF:
|
||||
/*
|
||||
* from: BUS_OFF
|
||||
/* from: BUS_OFF
|
||||
* to : ERROR_ACTIVE, ERROR_WARNING, ERROR_PASSIVE
|
||||
*/
|
||||
if (new_state <= CAN_STATE_ERROR_PASSIVE) {
|
||||
@ -935,12 +929,10 @@ static void at91_irq_err_state(struct net_device *dev,
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
/* process state changes depending on the new state */
|
||||
switch (new_state) {
|
||||
case CAN_STATE_ERROR_ACTIVE:
|
||||
/*
|
||||
* actually we want to enable AT91_IRQ_WARN here, but
|
||||
/* actually we want to enable AT91_IRQ_WARN here, but
|
||||
* it screws up the system under certain
|
||||
* circumstances. so just enable AT91_IRQ_ERRP, thus
|
||||
* the "fallthrough"
|
||||
@ -983,7 +975,7 @@ static void at91_irq_err_state(struct net_device *dev,
|
||||
}
|
||||
|
||||
static int at91_get_state_by_bec(const struct net_device *dev,
|
||||
enum can_state *state)
|
||||
enum can_state *state)
|
||||
{
|
||||
struct can_berr_counter bec;
|
||||
int err;
|
||||
@ -1004,7 +996,6 @@ static int at91_get_state_by_bec(const struct net_device *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void at91_irq_err(struct net_device *dev)
|
||||
{
|
||||
struct at91_priv *priv = netdev_priv(dev);
|
||||
@ -1018,15 +1009,15 @@ static void at91_irq_err(struct net_device *dev)
|
||||
reg_sr = at91_read(priv, AT91_SR);
|
||||
|
||||
/* we need to look at the unmasked reg_sr */
|
||||
if (unlikely(reg_sr & AT91_IRQ_BOFF))
|
||||
if (unlikely(reg_sr & AT91_IRQ_BOFF)) {
|
||||
new_state = CAN_STATE_BUS_OFF;
|
||||
else if (unlikely(reg_sr & AT91_IRQ_ERRP))
|
||||
} else if (unlikely(reg_sr & AT91_IRQ_ERRP)) {
|
||||
new_state = CAN_STATE_ERROR_PASSIVE;
|
||||
else if (unlikely(reg_sr & AT91_IRQ_WARN))
|
||||
} else if (unlikely(reg_sr & AT91_IRQ_WARN)) {
|
||||
new_state = CAN_STATE_ERROR_WARNING;
|
||||
else if (likely(reg_sr & AT91_IRQ_ERRA))
|
||||
} else if (likely(reg_sr & AT91_IRQ_ERRA)) {
|
||||
new_state = CAN_STATE_ERROR_ACTIVE;
|
||||
else {
|
||||
} else {
|
||||
netdev_err(dev, "BUG! hardware in undefined state\n");
|
||||
return;
|
||||
}
|
||||
@ -1053,8 +1044,7 @@ static void at91_irq_err(struct net_device *dev)
|
||||
priv->can.state = new_state;
|
||||
}
|
||||
|
||||
/*
|
||||
* interrupt handler
|
||||
/* interrupt handler
|
||||
*/
|
||||
static irqreturn_t at91_irq(int irq, void *dev_id)
|
||||
{
|
||||
@ -1075,8 +1065,7 @@ static irqreturn_t at91_irq(int irq, void *dev_id)
|
||||
|
||||
/* Receive or error interrupt? -> napi */
|
||||
if (reg_sr & (get_irq_mb_rx(priv) | AT91_IRQ_ERR_FRAME)) {
|
||||
/*
|
||||
* The error bits are clear on read,
|
||||
/* The error bits are clear on read,
|
||||
* save for later use.
|
||||
*/
|
||||
priv->reg_sr = reg_sr;
|
||||
@ -1133,8 +1122,7 @@ static int at91_open(struct net_device *dev)
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* stop CAN bus activity
|
||||
/* stop CAN bus activity
|
||||
*/
|
||||
static int at91_close(struct net_device *dev)
|
||||
{
|
||||
@ -1176,8 +1164,8 @@ static const struct net_device_ops at91_netdev_ops = {
|
||||
.ndo_change_mtu = can_change_mtu,
|
||||
};
|
||||
|
||||
static ssize_t at91_sysfs_show_mb0_id(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static ssize_t mb0_id_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct at91_priv *priv = netdev_priv(to_net_dev(dev));
|
||||
|
||||
@ -1187,8 +1175,9 @@ static ssize_t at91_sysfs_show_mb0_id(struct device *dev,
|
||||
return snprintf(buf, PAGE_SIZE, "0x%03x\n", priv->mb0_id);
|
||||
}
|
||||
|
||||
static ssize_t at91_sysfs_set_mb0_id(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t count)
|
||||
static ssize_t mb0_id_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct net_device *ndev = to_net_dev(dev);
|
||||
struct at91_priv *priv = netdev_priv(ndev);
|
||||
@ -1222,7 +1211,7 @@ static ssize_t at91_sysfs_set_mb0_id(struct device *dev,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(mb0_id, 0644, at91_sysfs_show_mb0_id, at91_sysfs_set_mb0_id);
|
||||
static DEVICE_ATTR_RW(mb0_id);
|
||||
|
||||
static struct attribute *at91_sysfs_attrs[] = {
|
||||
&dev_attr_mb0_id.attr,
|
||||
|
@ -47,7 +47,7 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[],
|
||||
}
|
||||
|
||||
if (data[IFLA_CAN_DATA_BITTIMING]) {
|
||||
if (!is_can_fd || !data[IFLA_CAN_BITTIMING])
|
||||
if (!is_can_fd)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
@ -132,10 +132,13 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
|
||||
priv->ctrlmode |= maskedflags;
|
||||
|
||||
/* CAN_CTRLMODE_FD can only be set when driver supports FD */
|
||||
if (priv->ctrlmode & CAN_CTRLMODE_FD)
|
||||
if (priv->ctrlmode & CAN_CTRLMODE_FD) {
|
||||
dev->mtu = CANFD_MTU;
|
||||
else
|
||||
} else {
|
||||
dev->mtu = CAN_MTU;
|
||||
memset(&priv->data_bittiming, 0,
|
||||
sizeof(priv->data_bittiming));
|
||||
}
|
||||
}
|
||||
|
||||
if (data[IFLA_CAN_RESTART_MS]) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Copyright (c) 2014 Protonic Holland,
|
||||
* David Jander
|
||||
* Copyright (C) 2014-2017 Pengutronix,
|
||||
* Copyright (C) 2014-2021 Pengutronix,
|
||||
* Marc Kleine-Budde <kernel@pengutronix.de>
|
||||
*/
|
||||
|
||||
@ -174,10 +174,8 @@ can_rx_offload_offload_one(struct can_rx_offload *offload, unsigned int n)
|
||||
int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload,
|
||||
u64 pending)
|
||||
{
|
||||
struct sk_buff_head skb_queue;
|
||||
unsigned int i;
|
||||
|
||||
__skb_queue_head_init(&skb_queue);
|
||||
int received = 0;
|
||||
|
||||
for (i = offload->mb_first;
|
||||
can_rx_offload_le(offload, i, offload->mb_last);
|
||||
@ -191,26 +189,12 @@ int can_rx_offload_irq_offload_timestamp(struct can_rx_offload *offload,
|
||||
if (IS_ERR_OR_NULL(skb))
|
||||
continue;
|
||||
|
||||
__skb_queue_add_sort(&skb_queue, skb, can_rx_offload_compare);
|
||||
__skb_queue_add_sort(&offload->skb_irq_queue, skb,
|
||||
can_rx_offload_compare);
|
||||
received++;
|
||||
}
|
||||
|
||||
if (!skb_queue_empty(&skb_queue)) {
|
||||
unsigned long flags;
|
||||
u32 queue_len;
|
||||
|
||||
spin_lock_irqsave(&offload->skb_queue.lock, flags);
|
||||
skb_queue_splice_tail(&skb_queue, &offload->skb_queue);
|
||||
spin_unlock_irqrestore(&offload->skb_queue.lock, flags);
|
||||
|
||||
queue_len = skb_queue_len(&offload->skb_queue);
|
||||
if (queue_len > offload->skb_queue_len_max / 8)
|
||||
netdev_dbg(offload->dev, "%s: queue_len=%d\n",
|
||||
__func__, queue_len);
|
||||
|
||||
can_rx_offload_schedule(offload);
|
||||
}
|
||||
|
||||
return skb_queue_len(&skb_queue);
|
||||
return received;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_rx_offload_irq_offload_timestamp);
|
||||
|
||||
@ -226,13 +210,10 @@ int can_rx_offload_irq_offload_fifo(struct can_rx_offload *offload)
|
||||
if (!skb)
|
||||
break;
|
||||
|
||||
skb_queue_tail(&offload->skb_queue, skb);
|
||||
__skb_queue_tail(&offload->skb_irq_queue, skb);
|
||||
received++;
|
||||
}
|
||||
|
||||
if (received)
|
||||
can_rx_offload_schedule(offload);
|
||||
|
||||
return received;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_rx_offload_irq_offload_fifo);
|
||||
@ -241,7 +222,6 @@ int can_rx_offload_queue_sorted(struct can_rx_offload *offload,
|
||||
struct sk_buff *skb, u32 timestamp)
|
||||
{
|
||||
struct can_rx_offload_cb *cb;
|
||||
unsigned long flags;
|
||||
|
||||
if (skb_queue_len(&offload->skb_queue) >
|
||||
offload->skb_queue_len_max) {
|
||||
@ -252,11 +232,8 @@ int can_rx_offload_queue_sorted(struct can_rx_offload *offload,
|
||||
cb = can_rx_offload_get_cb(skb);
|
||||
cb->timestamp = timestamp;
|
||||
|
||||
spin_lock_irqsave(&offload->skb_queue.lock, flags);
|
||||
__skb_queue_add_sort(&offload->skb_queue, skb, can_rx_offload_compare);
|
||||
spin_unlock_irqrestore(&offload->skb_queue.lock, flags);
|
||||
|
||||
can_rx_offload_schedule(offload);
|
||||
__skb_queue_add_sort(&offload->skb_irq_queue, skb,
|
||||
can_rx_offload_compare);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -295,13 +272,56 @@ int can_rx_offload_queue_tail(struct can_rx_offload *offload,
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
skb_queue_tail(&offload->skb_queue, skb);
|
||||
can_rx_offload_schedule(offload);
|
||||
__skb_queue_tail(&offload->skb_irq_queue, skb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_rx_offload_queue_tail);
|
||||
|
||||
void can_rx_offload_irq_finish(struct can_rx_offload *offload)
|
||||
{
|
||||
unsigned long flags;
|
||||
int queue_len;
|
||||
|
||||
if (skb_queue_empty_lockless(&offload->skb_irq_queue))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&offload->skb_queue.lock, flags);
|
||||
skb_queue_splice_tail_init(&offload->skb_irq_queue, &offload->skb_queue);
|
||||
spin_unlock_irqrestore(&offload->skb_queue.lock, flags);
|
||||
|
||||
queue_len = skb_queue_len(&offload->skb_queue);
|
||||
if (queue_len > offload->skb_queue_len_max / 8)
|
||||
netdev_dbg(offload->dev, "%s: queue_len=%d\n",
|
||||
__func__, queue_len);
|
||||
|
||||
napi_schedule(&offload->napi);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_rx_offload_irq_finish);
|
||||
|
||||
void can_rx_offload_threaded_irq_finish(struct can_rx_offload *offload)
|
||||
{
|
||||
unsigned long flags;
|
||||
int queue_len;
|
||||
|
||||
if (skb_queue_empty_lockless(&offload->skb_irq_queue))
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&offload->skb_queue.lock, flags);
|
||||
skb_queue_splice_tail_init(&offload->skb_irq_queue, &offload->skb_queue);
|
||||
spin_unlock_irqrestore(&offload->skb_queue.lock, flags);
|
||||
|
||||
queue_len = skb_queue_len(&offload->skb_queue);
|
||||
if (queue_len > offload->skb_queue_len_max / 8)
|
||||
netdev_dbg(offload->dev, "%s: queue_len=%d\n",
|
||||
__func__, queue_len);
|
||||
|
||||
local_bh_disable();
|
||||
napi_schedule(&offload->napi);
|
||||
local_bh_enable();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_rx_offload_threaded_irq_finish);
|
||||
|
||||
static int can_rx_offload_init_queue(struct net_device *dev,
|
||||
struct can_rx_offload *offload,
|
||||
unsigned int weight)
|
||||
@ -312,6 +332,7 @@ static int can_rx_offload_init_queue(struct net_device *dev,
|
||||
offload->skb_queue_len_max = 2 << fls(weight);
|
||||
offload->skb_queue_len_max *= 4;
|
||||
skb_queue_head_init(&offload->skb_queue);
|
||||
__skb_queue_head_init(&offload->skb_irq_queue);
|
||||
|
||||
netif_napi_add(dev, &offload->napi, can_rx_offload_napi_poll, weight);
|
||||
|
||||
@ -373,5 +394,6 @@ void can_rx_offload_del(struct can_rx_offload *offload)
|
||||
{
|
||||
netif_napi_del(&offload->napi);
|
||||
skb_queue_purge(&offload->skb_queue);
|
||||
__skb_queue_purge(&offload->skb_irq_queue);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_rx_offload_del);
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/can/platform/flexcan.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/regmap.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
@ -208,18 +209,19 @@
|
||||
/* FLEXCAN hardware feature flags
|
||||
*
|
||||
* Below is some version info we got:
|
||||
* SOC Version IP-Version Glitch- [TR]WRN_INT IRQ Err Memory err RTR rece- FD Mode
|
||||
* SOC Version IP-Version Glitch- [TR]WRN_INT IRQ Err Memory err RTR rece- FD Mode MB
|
||||
* Filter? connected? Passive detection ption in MB Supported?
|
||||
* MX25 FlexCAN2 03.00.00.00 no no no no no no
|
||||
* MX28 FlexCAN2 03.00.04.00 yes yes no no no no
|
||||
* MX35 FlexCAN2 03.00.00.00 no no no no no no
|
||||
* MX53 FlexCAN2 03.00.00.00 yes no no no no no
|
||||
* MX6s FlexCAN3 10.00.12.00 yes yes no no yes no
|
||||
* MX8QM FlexCAN3 03.00.23.00 yes yes no no yes yes
|
||||
* MX8MP FlexCAN3 03.00.17.01 yes yes no yes yes yes
|
||||
* VF610 FlexCAN3 ? no yes no yes yes? no
|
||||
* LS1021A FlexCAN2 03.00.04.00 no yes no no yes no
|
||||
* LX2160A FlexCAN3 03.00.23.00 no yes no yes yes yes
|
||||
* MCF5441X FlexCAN2 ? no yes no no yes no 16
|
||||
* MX25 FlexCAN2 03.00.00.00 no no no no no no 64
|
||||
* MX28 FlexCAN2 03.00.04.00 yes yes no no no no 64
|
||||
* MX35 FlexCAN2 03.00.00.00 no no no no no no 64
|
||||
* MX53 FlexCAN2 03.00.00.00 yes no no no no no 64
|
||||
* MX6s FlexCAN3 10.00.12.00 yes yes no no yes no 64
|
||||
* MX8QM FlexCAN3 03.00.23.00 yes yes no no yes yes 64
|
||||
* MX8MP FlexCAN3 03.00.17.01 yes yes no yes yes yes 64
|
||||
* VF610 FlexCAN3 ? no yes no yes yes? no 64
|
||||
* LS1021A FlexCAN2 03.00.04.00 no yes no no yes no 64
|
||||
* LX2160A FlexCAN3 03.00.23.00 no yes no yes yes yes 64
|
||||
*
|
||||
* Some SOCs do not have the RX_WARN & TX_WARN interrupt line connected.
|
||||
*/
|
||||
@ -246,6 +248,10 @@
|
||||
#define FLEXCAN_QUIRK_SUPPORT_ECC BIT(10)
|
||||
/* Setup stop mode with SCU firmware to support wakeup */
|
||||
#define FLEXCAN_QUIRK_SETUP_STOP_MODE_SCFW BIT(11)
|
||||
/* Setup 3 separate interrupts, main, boff and err */
|
||||
#define FLEXCAN_QUIRK_NR_IRQ_3 BIT(12)
|
||||
/* Setup 16 mailboxes */
|
||||
#define FLEXCAN_QUIRK_NR_MB_16 BIT(13)
|
||||
|
||||
/* Structure of the message buffer */
|
||||
struct flexcan_mb {
|
||||
@ -363,6 +369,9 @@ struct flexcan_priv {
|
||||
struct regulator *reg_xceiver;
|
||||
struct flexcan_stop_mode stm;
|
||||
|
||||
int irq_boff;
|
||||
int irq_err;
|
||||
|
||||
/* IPC handle when setup stop mode by System Controller firmware(scfw) */
|
||||
struct imx_sc_ipc *sc_ipc_handle;
|
||||
|
||||
@ -371,6 +380,11 @@ struct flexcan_priv {
|
||||
void (*write)(u32 val, void __iomem *addr);
|
||||
};
|
||||
|
||||
static const struct flexcan_devtype_data fsl_mcf5441x_devtype_data = {
|
||||
.quirks = FLEXCAN_QUIRK_BROKEN_PERR_STATE |
|
||||
FLEXCAN_QUIRK_NR_IRQ_3 | FLEXCAN_QUIRK_NR_MB_16,
|
||||
};
|
||||
|
||||
static const struct flexcan_devtype_data fsl_p1010_devtype_data = {
|
||||
.quirks = FLEXCAN_QUIRK_BROKEN_WERR_STATE |
|
||||
FLEXCAN_QUIRK_BROKEN_PERR_STATE |
|
||||
@ -637,13 +651,17 @@ static int flexcan_clks_enable(const struct flexcan_priv *priv)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = clk_prepare_enable(priv->clk_ipg);
|
||||
if (err)
|
||||
return err;
|
||||
if (priv->clk_ipg) {
|
||||
err = clk_prepare_enable(priv->clk_ipg);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
err = clk_prepare_enable(priv->clk_per);
|
||||
if (err)
|
||||
clk_disable_unprepare(priv->clk_ipg);
|
||||
if (priv->clk_per) {
|
||||
err = clk_prepare_enable(priv->clk_per);
|
||||
if (err)
|
||||
clk_disable_unprepare(priv->clk_ipg);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -1198,6 +1216,9 @@ static irqreturn_t flexcan_irq(int irq, void *dev_id)
|
||||
}
|
||||
}
|
||||
|
||||
if (handled)
|
||||
can_rx_offload_irq_finish(&priv->offload);
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
@ -1401,8 +1422,12 @@ static int flexcan_rx_offload_setup(struct net_device *dev)
|
||||
priv->mb_size = sizeof(struct flexcan_mb) + CANFD_MAX_DLEN;
|
||||
else
|
||||
priv->mb_size = sizeof(struct flexcan_mb) + CAN_MAX_DLEN;
|
||||
priv->mb_count = (sizeof(priv->regs->mb[0]) / priv->mb_size) +
|
||||
(sizeof(priv->regs->mb[1]) / priv->mb_size);
|
||||
|
||||
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_NR_MB_16)
|
||||
priv->mb_count = 16;
|
||||
else
|
||||
priv->mb_count = (sizeof(priv->regs->mb[0]) / priv->mb_size) +
|
||||
(sizeof(priv->regs->mb[1]) / priv->mb_size);
|
||||
|
||||
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP)
|
||||
priv->tx_mb_reserved =
|
||||
@ -1774,6 +1799,18 @@ static int flexcan_open(struct net_device *dev)
|
||||
if (err)
|
||||
goto out_can_rx_offload_disable;
|
||||
|
||||
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
|
||||
err = request_irq(priv->irq_boff,
|
||||
flexcan_irq, IRQF_SHARED, dev->name, dev);
|
||||
if (err)
|
||||
goto out_free_irq;
|
||||
|
||||
err = request_irq(priv->irq_err,
|
||||
flexcan_irq, IRQF_SHARED, dev->name, dev);
|
||||
if (err)
|
||||
goto out_free_irq_boff;
|
||||
}
|
||||
|
||||
flexcan_chip_interrupts_enable(dev);
|
||||
|
||||
can_led_event(dev, CAN_LED_EVENT_OPEN);
|
||||
@ -1782,6 +1819,10 @@ static int flexcan_open(struct net_device *dev)
|
||||
|
||||
return 0;
|
||||
|
||||
out_free_irq_boff:
|
||||
free_irq(priv->irq_boff, dev);
|
||||
out_free_irq:
|
||||
free_irq(dev->irq, dev);
|
||||
out_can_rx_offload_disable:
|
||||
can_rx_offload_disable(&priv->offload);
|
||||
flexcan_chip_stop(dev);
|
||||
@ -1803,6 +1844,12 @@ static int flexcan_close(struct net_device *dev)
|
||||
|
||||
netif_stop_queue(dev);
|
||||
flexcan_chip_interrupts_disable(dev);
|
||||
|
||||
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
|
||||
free_irq(priv->irq_err, dev);
|
||||
free_irq(priv->irq_boff, dev);
|
||||
}
|
||||
|
||||
free_irq(dev->irq, dev);
|
||||
can_rx_offload_disable(&priv->offload);
|
||||
flexcan_chip_stop_disable_on_error(dev);
|
||||
@ -2039,14 +2086,26 @@ static const struct of_device_id flexcan_of_match[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, flexcan_of_match);
|
||||
|
||||
static const struct platform_device_id flexcan_id_table[] = {
|
||||
{
|
||||
.name = "flexcan-mcf5441x",
|
||||
.driver_data = (kernel_ulong_t)&fsl_mcf5441x_devtype_data,
|
||||
}, {
|
||||
/* sentinel */
|
||||
},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(platform, flexcan_id_table);
|
||||
|
||||
static int flexcan_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct of_device_id *of_id;
|
||||
const struct flexcan_devtype_data *devtype_data;
|
||||
struct net_device *dev;
|
||||
struct flexcan_priv *priv;
|
||||
struct regulator *reg_xceiver;
|
||||
struct clk *clk_ipg = NULL, *clk_per = NULL;
|
||||
struct flexcan_regs __iomem *regs;
|
||||
struct flexcan_platform_data *pdata;
|
||||
int err, irq;
|
||||
u8 clk_src = 1;
|
||||
u32 clock_freq = 0;
|
||||
@ -2064,6 +2123,12 @@ static int flexcan_probe(struct platform_device *pdev)
|
||||
"clock-frequency", &clock_freq);
|
||||
of_property_read_u8(pdev->dev.of_node,
|
||||
"fsl,clk-source", &clk_src);
|
||||
} else {
|
||||
pdata = dev_get_platdata(&pdev->dev);
|
||||
if (pdata) {
|
||||
clock_freq = pdata->clock_frequency;
|
||||
clk_src = pdata->clk_src;
|
||||
}
|
||||
}
|
||||
|
||||
if (!clock_freq) {
|
||||
@ -2089,7 +2154,14 @@ static int flexcan_probe(struct platform_device *pdev)
|
||||
if (IS_ERR(regs))
|
||||
return PTR_ERR(regs);
|
||||
|
||||
devtype_data = of_device_get_match_data(&pdev->dev);
|
||||
of_id = of_match_device(flexcan_of_match, &pdev->dev);
|
||||
if (of_id)
|
||||
devtype_data = of_id->data;
|
||||
else if (platform_get_device_id(pdev)->driver_data)
|
||||
devtype_data = (struct flexcan_devtype_data *)
|
||||
platform_get_device_id(pdev)->driver_data;
|
||||
else
|
||||
return -ENODEV;
|
||||
|
||||
if ((devtype_data->quirks & FLEXCAN_QUIRK_SUPPORT_FD) &&
|
||||
!(devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP)) {
|
||||
@ -2133,6 +2205,19 @@ static int flexcan_probe(struct platform_device *pdev)
|
||||
priv->devtype_data = devtype_data;
|
||||
priv->reg_xceiver = reg_xceiver;
|
||||
|
||||
if (devtype_data->quirks & FLEXCAN_QUIRK_NR_IRQ_3) {
|
||||
priv->irq_boff = platform_get_irq(pdev, 1);
|
||||
if (priv->irq_boff <= 0) {
|
||||
err = -ENODEV;
|
||||
goto failed_platform_get_irq;
|
||||
}
|
||||
priv->irq_err = platform_get_irq(pdev, 2);
|
||||
if (priv->irq_err <= 0) {
|
||||
err = -ENODEV;
|
||||
goto failed_platform_get_irq;
|
||||
}
|
||||
}
|
||||
|
||||
if (priv->devtype_data->quirks & FLEXCAN_QUIRK_SUPPORT_FD) {
|
||||
priv->can.ctrlmode_supported |= CAN_CTRLMODE_FD |
|
||||
CAN_CTRLMODE_FD_NON_ISO;
|
||||
@ -2170,6 +2255,7 @@ static int flexcan_probe(struct platform_device *pdev)
|
||||
failed_register:
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
failed_platform_get_irq:
|
||||
free_candev(dev);
|
||||
return err;
|
||||
}
|
||||
@ -2322,6 +2408,7 @@ static struct platform_driver flexcan_driver = {
|
||||
},
|
||||
.probe = flexcan_probe,
|
||||
.remove = flexcan_remove,
|
||||
.id_table = flexcan_id_table,
|
||||
};
|
||||
|
||||
module_platform_driver(flexcan_driver);
|
||||
|
@ -1815,9 +1815,9 @@ static int ican3_get_berr_counter(const struct net_device *ndev,
|
||||
* Sysfs Attributes
|
||||
*/
|
||||
|
||||
static ssize_t ican3_sysfs_show_term(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
static ssize_t termination_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ican3_dev *mod = netdev_priv(to_net_dev(dev));
|
||||
int ret;
|
||||
@ -1834,9 +1834,9 @@ static ssize_t ican3_sysfs_show_term(struct device *dev,
|
||||
return snprintf(buf, PAGE_SIZE, "%u\n", mod->termination_enabled);
|
||||
}
|
||||
|
||||
static ssize_t ican3_sysfs_set_term(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
static ssize_t termination_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct ican3_dev *mod = netdev_priv(to_net_dev(dev));
|
||||
unsigned long enable;
|
||||
@ -1852,18 +1852,17 @@ static ssize_t ican3_sysfs_set_term(struct device *dev,
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t ican3_sysfs_show_fwinfo(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
static ssize_t fwinfo_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct ican3_dev *mod = netdev_priv(to_net_dev(dev));
|
||||
|
||||
return scnprintf(buf, PAGE_SIZE, "%s\n", mod->fwinfo);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(termination, 0644, ican3_sysfs_show_term,
|
||||
ican3_sysfs_set_term);
|
||||
static DEVICE_ATTR(fwinfo, 0444, ican3_sysfs_show_fwinfo, NULL);
|
||||
static DEVICE_ATTR_RW(termination);
|
||||
static DEVICE_ATTR_RO(fwinfo);
|
||||
|
||||
static struct attribute *ican3_sysfs_attrs[] = {
|
||||
&dev_attr_termination.attr,
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/can/dev.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/phy/phy.h>
|
||||
|
||||
#include "m_can.h"
|
||||
|
||||
@ -1058,6 +1059,9 @@ static irqreturn_t m_can_isr(int irq, void *dev_id)
|
||||
}
|
||||
}
|
||||
|
||||
if (cdev->is_peripheral)
|
||||
can_rx_offload_threaded_irq_finish(&cdev->offload);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
@ -1436,32 +1440,20 @@ static int m_can_dev_setup(struct m_can_classdev *cdev)
|
||||
case 30:
|
||||
/* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.0.x */
|
||||
can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO);
|
||||
cdev->can.bittiming_const = cdev->bit_timing ?
|
||||
cdev->bit_timing : &m_can_bittiming_const_30X;
|
||||
|
||||
cdev->can.data_bittiming_const = cdev->data_timing ?
|
||||
cdev->data_timing :
|
||||
&m_can_data_bittiming_const_30X;
|
||||
cdev->can.bittiming_const = &m_can_bittiming_const_30X;
|
||||
cdev->can.data_bittiming_const = &m_can_data_bittiming_const_30X;
|
||||
break;
|
||||
case 31:
|
||||
/* CAN_CTRLMODE_FD_NON_ISO is fixed with M_CAN IP v3.1.x */
|
||||
can_set_static_ctrlmode(dev, CAN_CTRLMODE_FD_NON_ISO);
|
||||
cdev->can.bittiming_const = cdev->bit_timing ?
|
||||
cdev->bit_timing : &m_can_bittiming_const_31X;
|
||||
|
||||
cdev->can.data_bittiming_const = cdev->data_timing ?
|
||||
cdev->data_timing :
|
||||
&m_can_data_bittiming_const_31X;
|
||||
cdev->can.bittiming_const = &m_can_bittiming_const_31X;
|
||||
cdev->can.data_bittiming_const = &m_can_data_bittiming_const_31X;
|
||||
break;
|
||||
case 32:
|
||||
case 33:
|
||||
/* Support both MCAN version v3.2.x and v3.3.0 */
|
||||
cdev->can.bittiming_const = cdev->bit_timing ?
|
||||
cdev->bit_timing : &m_can_bittiming_const_31X;
|
||||
|
||||
cdev->can.data_bittiming_const = cdev->data_timing ?
|
||||
cdev->data_timing :
|
||||
&m_can_data_bittiming_const_31X;
|
||||
cdev->can.bittiming_const = &m_can_bittiming_const_31X;
|
||||
cdev->can.data_bittiming_const = &m_can_data_bittiming_const_31X;
|
||||
|
||||
cdev->can.ctrlmode_supported |=
|
||||
(m_can_niso_supported(cdev) ?
|
||||
@ -1518,6 +1510,8 @@ static int m_can_close(struct net_device *dev)
|
||||
close_candev(dev);
|
||||
can_led_event(dev, CAN_LED_EVENT_STOP);
|
||||
|
||||
phy_power_off(cdev->transceiver);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -1703,10 +1697,14 @@ static int m_can_open(struct net_device *dev)
|
||||
struct m_can_classdev *cdev = netdev_priv(dev);
|
||||
int err;
|
||||
|
||||
err = m_can_clk_start(cdev);
|
||||
err = phy_power_on(cdev->transceiver);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = m_can_clk_start(cdev);
|
||||
if (err)
|
||||
goto out_phy_power_off;
|
||||
|
||||
/* open the can device */
|
||||
err = open_candev(dev);
|
||||
if (err) {
|
||||
@ -1763,6 +1761,8 @@ out_wq_fail:
|
||||
close_candev(dev);
|
||||
exit_disable_clks:
|
||||
m_can_clk_stop(cdev);
|
||||
out_phy_power_off:
|
||||
phy_power_off(cdev->transceiver);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/can/dev.h>
|
||||
#include <linux/pinctrl/consumer.h>
|
||||
#include <linux/phy/phy.h>
|
||||
|
||||
/* m_can lec values */
|
||||
enum m_can_lec_type {
|
||||
@ -82,9 +83,7 @@ struct m_can_classdev {
|
||||
struct workqueue_struct *tx_wq;
|
||||
struct work_struct tx_work;
|
||||
struct sk_buff *tx_skb;
|
||||
|
||||
struct can_bittiming_const *bit_timing;
|
||||
struct can_bittiming_const *data_timing;
|
||||
struct phy *transceiver;
|
||||
|
||||
struct m_can_ops *ops;
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
// Copyright (C) 2018-19 Texas Instruments Incorporated - http://www.ti.com/
|
||||
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/phy/phy.h>
|
||||
|
||||
#include "m_can.h"
|
||||
|
||||
@ -67,6 +68,7 @@ static int m_can_plat_probe(struct platform_device *pdev)
|
||||
struct resource *res;
|
||||
void __iomem *addr;
|
||||
void __iomem *mram_addr;
|
||||
struct phy *transceiver;
|
||||
int irq, ret = 0;
|
||||
|
||||
mcan_class = m_can_class_allocate_dev(&pdev->dev,
|
||||
@ -80,8 +82,7 @@ static int m_can_plat_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto probe_fail;
|
||||
|
||||
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "m_can");
|
||||
addr = devm_ioremap_resource(&pdev->dev, res);
|
||||
addr = devm_platform_ioremap_resource_byname(pdev, "m_can");
|
||||
irq = platform_get_irq_byname(pdev, "int0");
|
||||
if (IS_ERR(addr) || irq < 0) {
|
||||
ret = -EINVAL;
|
||||
@ -101,6 +102,16 @@ static int m_can_plat_probe(struct platform_device *pdev)
|
||||
goto probe_fail;
|
||||
}
|
||||
|
||||
transceiver = devm_phy_optional_get(&pdev->dev, NULL);
|
||||
if (IS_ERR(transceiver)) {
|
||||
ret = PTR_ERR(transceiver);
|
||||
dev_err_probe(&pdev->dev, ret, "failed to get phy\n");
|
||||
goto probe_fail;
|
||||
}
|
||||
|
||||
if (transceiver)
|
||||
mcan_class->can.bitrate_max = transceiver->attrs.max_link_rate;
|
||||
|
||||
priv->base = addr;
|
||||
priv->mram_base = mram_addr;
|
||||
|
||||
@ -108,6 +119,7 @@ static int m_can_plat_probe(struct platform_device *pdev)
|
||||
mcan_class->pm_clock_support = 1;
|
||||
mcan_class->can.clock.freq = clk_get_rate(mcan_class->cclk);
|
||||
mcan_class->dev = &pdev->dev;
|
||||
mcan_class->transceiver = transceiver;
|
||||
|
||||
mcan_class->ops = &m_can_plat_ops;
|
||||
|
||||
|
@ -28,6 +28,10 @@ MODULE_LICENSE("GPL v2");
|
||||
|
||||
#define DRV_NAME "peak_pci"
|
||||
|
||||
/* FPGA cards FW version registers */
|
||||
#define PEAK_VER_REG1 0x40
|
||||
#define PEAK_VER_REG2 0x44
|
||||
|
||||
struct peak_pciec_card;
|
||||
struct peak_pci_chan {
|
||||
void __iomem *cfg_base; /* Common for all channels */
|
||||
@ -41,9 +45,7 @@ struct peak_pci_chan {
|
||||
#define PEAK_PCI_CDR (CDR_CBP | CDR_CLKOUT_MASK)
|
||||
#define PEAK_PCI_OCR OCR_TX0_PUSHPULL
|
||||
|
||||
/*
|
||||
* Important PITA registers
|
||||
*/
|
||||
/* Important PITA registers */
|
||||
#define PITA_ICR 0x00 /* Interrupt control register */
|
||||
#define PITA_GPIOICR 0x18 /* GPIO interface control register */
|
||||
#define PITA_MISC 0x1C /* Miscellaneous register */
|
||||
@ -70,27 +72,47 @@ static const u16 peak_pci_icr_masks[PEAK_PCI_CHAN_MAX] = {
|
||||
};
|
||||
|
||||
static const struct pci_device_id peak_pci_tbl[] = {
|
||||
{PEAK_PCI_VENDOR_ID, PEAK_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
|
||||
{PEAK_PCI_VENDOR_ID, PEAK_PCIE_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
|
||||
{PEAK_PCI_VENDOR_ID, PEAK_MPCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
|
||||
{PEAK_PCI_VENDOR_ID, PEAK_MPCIE_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
|
||||
{PEAK_PCI_VENDOR_ID, PEAK_PC_104P_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
|
||||
{PEAK_PCI_VENDOR_ID, PEAK_PCI_104E_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
|
||||
{PEAK_PCI_VENDOR_ID, PEAK_CPCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
|
||||
{PEAK_PCI_VENDOR_ID, PEAK_PCIE_OEM_ID, PCI_ANY_ID, PCI_ANY_ID,},
|
||||
{
|
||||
PEAK_PCI_VENDOR_ID, PEAK_PCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,
|
||||
.driver_data = (kernel_ulong_t)"PCAN-PCI",
|
||||
}, {
|
||||
PEAK_PCI_VENDOR_ID, PEAK_PCIE_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,
|
||||
.driver_data = (kernel_ulong_t)"PCAN-PCI Express",
|
||||
}, {
|
||||
PEAK_PCI_VENDOR_ID, PEAK_MPCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,
|
||||
.driver_data = (kernel_ulong_t)"PCAN-miniPCI",
|
||||
}, {
|
||||
PEAK_PCI_VENDOR_ID, PEAK_MPCIE_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,
|
||||
.driver_data = (kernel_ulong_t)"PCAN-miniPCIe",
|
||||
}, {
|
||||
PEAK_PCI_VENDOR_ID, PEAK_PC_104P_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,
|
||||
.driver_data = (kernel_ulong_t)"PCAN-PC/104-Plus Quad",
|
||||
}, {
|
||||
PEAK_PCI_VENDOR_ID, PEAK_PCI_104E_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,
|
||||
.driver_data = (kernel_ulong_t)"PCAN-PCI/104-Express",
|
||||
}, {
|
||||
PEAK_PCI_VENDOR_ID, PEAK_CPCI_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,
|
||||
.driver_data = (kernel_ulong_t)"PCAN-cPCI",
|
||||
}, {
|
||||
PEAK_PCI_VENDOR_ID, PEAK_PCIE_OEM_ID, PCI_ANY_ID, PCI_ANY_ID,
|
||||
.driver_data = (kernel_ulong_t)"PCAN-Chip PCIe",
|
||||
},
|
||||
#ifdef CONFIG_CAN_PEAK_PCIEC
|
||||
{PEAK_PCI_VENDOR_ID, PEAK_PCIEC_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
|
||||
{PEAK_PCI_VENDOR_ID, PEAK_PCIEC34_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
|
||||
{
|
||||
PEAK_PCI_VENDOR_ID, PEAK_PCIEC_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,
|
||||
.driver_data = (kernel_ulong_t)"PCAN-ExpressCard",
|
||||
}, {
|
||||
PEAK_PCI_VENDOR_ID, PEAK_PCIEC34_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,
|
||||
.driver_data = (kernel_ulong_t)"PCAN-ExpressCard 34",
|
||||
},
|
||||
#endif
|
||||
{0,}
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pci, peak_pci_tbl);
|
||||
|
||||
#ifdef CONFIG_CAN_PEAK_PCIEC
|
||||
/*
|
||||
* PCAN-ExpressCard needs I2C bit-banging configuration option.
|
||||
*/
|
||||
/* PCAN-ExpressCard needs I2C bit-banging configuration option. */
|
||||
|
||||
/* GPIOICR byte access offsets */
|
||||
#define PITA_GPOUT 0x18 /* GPx output value */
|
||||
@ -156,12 +178,14 @@ static void peak_pci_write_reg(const struct sja1000_priv *priv,
|
||||
static inline void pita_set_scl_highz(struct peak_pciec_card *card)
|
||||
{
|
||||
u8 gp_outen = readb(card->cfg_base + PITA_GPOEN) & ~PITA_GPIN_SCL;
|
||||
|
||||
writeb(gp_outen, card->cfg_base + PITA_GPOEN);
|
||||
}
|
||||
|
||||
static inline void pita_set_sda_highz(struct peak_pciec_card *card)
|
||||
{
|
||||
u8 gp_outen = readb(card->cfg_base + PITA_GPOEN) & ~PITA_GPIN_SDA;
|
||||
|
||||
writeb(gp_outen, card->cfg_base + PITA_GPOEN);
|
||||
}
|
||||
|
||||
@ -230,9 +254,7 @@ static int pita_getscl(void *data)
|
||||
return (readb(card->cfg_base + PITA_GPIN) & PITA_GPIN_SCL) ? 1 : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* write commands to the LED chip though the I2C-bus of the PCAN-PCIeC
|
||||
*/
|
||||
/* write commands to the LED chip though the I2C-bus of the PCAN-PCIeC */
|
||||
static int peak_pciec_write_pca9553(struct peak_pciec_card *card,
|
||||
u8 offset, u8 data)
|
||||
{
|
||||
@ -248,7 +270,7 @@ static int peak_pciec_write_pca9553(struct peak_pciec_card *card,
|
||||
int ret;
|
||||
|
||||
/* cache led mask */
|
||||
if ((offset == 5) && (data == card->led_cache))
|
||||
if (offset == 5 && data == card->led_cache)
|
||||
return 0;
|
||||
|
||||
ret = i2c_transfer(&card->led_chip, &msg, 1);
|
||||
@ -261,9 +283,7 @@ static int peak_pciec_write_pca9553(struct peak_pciec_card *card,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* delayed work callback used to control the LEDs
|
||||
*/
|
||||
/* delayed work callback used to control the LEDs */
|
||||
static void peak_pciec_led_work(struct work_struct *work)
|
||||
{
|
||||
struct peak_pciec_card *card =
|
||||
@ -309,9 +329,7 @@ static void peak_pciec_led_work(struct work_struct *work)
|
||||
schedule_delayed_work(&card->led_work, HZ);
|
||||
}
|
||||
|
||||
/*
|
||||
* set LEDs blinking state
|
||||
*/
|
||||
/* set LEDs blinking state */
|
||||
static void peak_pciec_set_leds(struct peak_pciec_card *card, u8 led_mask, u8 s)
|
||||
{
|
||||
u8 new_led = card->led_cache;
|
||||
@ -328,25 +346,19 @@ static void peak_pciec_set_leds(struct peak_pciec_card *card, u8 led_mask, u8 s)
|
||||
peak_pciec_write_pca9553(card, 5, new_led);
|
||||
}
|
||||
|
||||
/*
|
||||
* start one second delayed work to control LEDs
|
||||
*/
|
||||
/* start one second delayed work to control LEDs */
|
||||
static void peak_pciec_start_led_work(struct peak_pciec_card *card)
|
||||
{
|
||||
schedule_delayed_work(&card->led_work, HZ);
|
||||
}
|
||||
|
||||
/*
|
||||
* stop LEDs delayed work
|
||||
*/
|
||||
/* stop LEDs delayed work */
|
||||
static void peak_pciec_stop_led_work(struct peak_pciec_card *card)
|
||||
{
|
||||
cancel_delayed_work_sync(&card->led_work);
|
||||
}
|
||||
|
||||
/*
|
||||
* initialize the PCA9553 4-bit I2C-bus LED chip
|
||||
*/
|
||||
/* initialize the PCA9553 4-bit I2C-bus LED chip */
|
||||
static int peak_pciec_init_leds(struct peak_pciec_card *card)
|
||||
{
|
||||
int err;
|
||||
@ -375,17 +387,14 @@ static int peak_pciec_init_leds(struct peak_pciec_card *card)
|
||||
return peak_pciec_write_pca9553(card, 5, PCA9553_LS0_INIT);
|
||||
}
|
||||
|
||||
/*
|
||||
* restore LEDs state to off peak_pciec_leds_exit
|
||||
*/
|
||||
/* restore LEDs state to off peak_pciec_leds_exit */
|
||||
static void peak_pciec_leds_exit(struct peak_pciec_card *card)
|
||||
{
|
||||
/* switch LEDs to off */
|
||||
peak_pciec_write_pca9553(card, 5, PCA9553_LED_OFF_ALL);
|
||||
}
|
||||
|
||||
/*
|
||||
* normal write sja1000 register method overloaded to catch when controller
|
||||
/* normal write sja1000 register method overloaded to catch when controller
|
||||
* is started or stopped, to control leds
|
||||
*/
|
||||
static void peak_pciec_write_reg(const struct sja1000_priv *priv,
|
||||
@ -443,7 +452,7 @@ static int peak_pciec_probe(struct pci_dev *pdev, struct net_device *dev)
|
||||
/* channel is the first one: do the init part */
|
||||
} else {
|
||||
/* create the bit banging I2C adapter structure */
|
||||
card = kzalloc(sizeof(struct peak_pciec_card), GFP_KERNEL);
|
||||
card = kzalloc(sizeof(*card), GFP_KERNEL);
|
||||
if (!card)
|
||||
return -ENOMEM;
|
||||
|
||||
@ -506,9 +515,7 @@ static void peak_pciec_remove(struct peak_pciec_card *card)
|
||||
|
||||
#else /* CONFIG_CAN_PEAK_PCIEC */
|
||||
|
||||
/*
|
||||
* Placebo functions when PCAN-ExpressCard support is not selected
|
||||
*/
|
||||
/* Placebo functions when PCAN-ExpressCard support is not selected */
|
||||
static inline int peak_pciec_probe(struct pci_dev *pdev, struct net_device *dev)
|
||||
{
|
||||
return -ENODEV;
|
||||
@ -549,6 +556,7 @@ static int peak_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
void __iomem *cfg_base, *reg_base;
|
||||
u16 sub_sys_id, icr;
|
||||
int i, err, channels;
|
||||
char fw_str[14] = "";
|
||||
|
||||
err = pci_enable_device(pdev);
|
||||
if (err)
|
||||
@ -602,6 +610,21 @@ static int peak_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
/* Leave parport mux mode */
|
||||
writeb(0x04, cfg_base + PITA_MISC + 3);
|
||||
|
||||
/* FPGA equipped card if not 0 */
|
||||
if (readl(cfg_base + PEAK_VER_REG1)) {
|
||||
/* FPGA card: display version of the running firmware */
|
||||
u32 fw_ver = readl(cfg_base + PEAK_VER_REG2);
|
||||
|
||||
snprintf(fw_str, sizeof(fw_str), " FW v%u.%u.%u",
|
||||
(fw_ver >> 12) & 0xf,
|
||||
(fw_ver >> 8) & 0xf,
|
||||
(fw_ver >> 4) & 0xf);
|
||||
}
|
||||
|
||||
/* Display commercial name (and, eventually, FW version) of the card */
|
||||
dev_info(&pdev->dev, "%ux CAN %s%s\n",
|
||||
channels, (const char *)ent->driver_data, fw_str);
|
||||
|
||||
icr = readw(cfg_base + PITA_ICR + 2);
|
||||
|
||||
for (i = 0; i < channels; i++) {
|
||||
@ -642,8 +665,7 @@ static int peak_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
chan->prev_dev = pci_get_drvdata(pdev);
|
||||
pci_set_drvdata(pdev, dev);
|
||||
|
||||
/*
|
||||
* PCAN-ExpressCard needs some additional i2c init.
|
||||
/* PCAN-ExpressCard needs some additional i2c init.
|
||||
* This must be done *before* register_sja1000dev() but
|
||||
* *after* devices linkage
|
||||
*/
|
||||
@ -709,7 +731,8 @@ failure_disable_pci:
|
||||
|
||||
/* pci_xxx_config_word() return positive PCIBIOS_xxx error codes while
|
||||
* the probe() function must return a negative errno in case of failure
|
||||
* (err is unchanged if negative) */
|
||||
* (err is unchanged if negative)
|
||||
*/
|
||||
return pcibios_err_to_errno(err);
|
||||
}
|
||||
|
||||
|
@ -15,10 +15,10 @@
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/pm_runtime.h>
|
||||
#include <linux/property.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
@ -2195,8 +2195,10 @@ static irqreturn_t mcp251xfd_irq(int irq, void *dev_id)
|
||||
FIELD_GET(MCP251XFD_REG_INT_IE_MASK,
|
||||
priv->regs_status.intf);
|
||||
|
||||
if (!(intf_pending))
|
||||
if (!(intf_pending)) {
|
||||
can_rx_offload_threaded_irq_finish(&priv->offload);
|
||||
return handled;
|
||||
}
|
||||
|
||||
/* Some interrupts must be ACKed in the
|
||||
* MCP251XFD_REG_INT register.
|
||||
@ -2296,6 +2298,8 @@ static irqreturn_t mcp251xfd_irq(int irq, void *dev_id)
|
||||
} while (1);
|
||||
|
||||
out_fail:
|
||||
can_rx_offload_threaded_irq_finish(&priv->offload);
|
||||
|
||||
netdev_err(priv->ndev, "IRQ handler returned %d (intf=0x%08x).\n",
|
||||
err, priv->regs_status.intf);
|
||||
mcp251xfd_dump(priv);
|
||||
@ -2523,8 +2527,8 @@ static int mcp251xfd_open(struct net_device *ndev)
|
||||
can_rx_offload_enable(&priv->offload);
|
||||
|
||||
err = request_threaded_irq(spi->irq, NULL, mcp251xfd_irq,
|
||||
IRQF_ONESHOT, dev_name(&spi->dev),
|
||||
priv);
|
||||
IRQF_SHARED | IRQF_ONESHOT,
|
||||
dev_name(&spi->dev), priv);
|
||||
if (err)
|
||||
goto out_can_rx_offload_disable;
|
||||
|
||||
@ -2856,7 +2860,7 @@ static int mcp251xfd_probe(struct spi_device *spi)
|
||||
struct gpio_desc *rx_int;
|
||||
struct regulator *reg_vdd, *reg_xceiver;
|
||||
struct clk *clk;
|
||||
u32 freq;
|
||||
u32 freq = 0;
|
||||
int err;
|
||||
|
||||
if (!spi->irq)
|
||||
@ -2883,11 +2887,19 @@ static int mcp251xfd_probe(struct spi_device *spi)
|
||||
return dev_err_probe(&spi->dev, PTR_ERR(reg_xceiver),
|
||||
"Failed to get Transceiver regulator!\n");
|
||||
|
||||
clk = devm_clk_get(&spi->dev, NULL);
|
||||
clk = devm_clk_get_optional(&spi->dev, NULL);
|
||||
if (IS_ERR(clk))
|
||||
return dev_err_probe(&spi->dev, PTR_ERR(clk),
|
||||
"Failed to get Oscillator (clock)!\n");
|
||||
freq = clk_get_rate(clk);
|
||||
if (clk) {
|
||||
freq = clk_get_rate(clk);
|
||||
} else {
|
||||
err = device_property_read_u32(&spi->dev, "clock-frequency",
|
||||
&freq);
|
||||
if (err)
|
||||
return dev_err_probe(&spi->dev, err,
|
||||
"Failed to get clock-frequency!\n");
|
||||
}
|
||||
|
||||
/* Sanity check */
|
||||
if (freq < MCP251XFD_SYSCLOCK_HZ_MIN ||
|
||||
|
@ -786,6 +786,8 @@ static irqreturn_t ti_hecc_interrupt(int irq, void *dev_id)
|
||||
int_status = hecc_read(priv, HECC_CANGIF0);
|
||||
}
|
||||
|
||||
can_rx_offload_irq_finish(&priv->offload);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
|
@ -474,7 +474,7 @@ static void esd_usb2_write_bulk_callback(struct urb *urb)
|
||||
netif_trans_update(netdev);
|
||||
}
|
||||
|
||||
static ssize_t show_firmware(struct device *d,
|
||||
static ssize_t firmware_show(struct device *d,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(d);
|
||||
@ -485,9 +485,9 @@ static ssize_t show_firmware(struct device *d,
|
||||
(dev->version >> 8) & 0xf,
|
||||
dev->version & 0xff);
|
||||
}
|
||||
static DEVICE_ATTR(firmware, 0444, show_firmware, NULL);
|
||||
static DEVICE_ATTR_RO(firmware);
|
||||
|
||||
static ssize_t show_hardware(struct device *d,
|
||||
static ssize_t hardware_show(struct device *d,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(d);
|
||||
@ -498,9 +498,9 @@ static ssize_t show_hardware(struct device *d,
|
||||
(dev->version >> 24) & 0xf,
|
||||
(dev->version >> 16) & 0xff);
|
||||
}
|
||||
static DEVICE_ATTR(hardware, 0444, show_hardware, NULL);
|
||||
static DEVICE_ATTR_RO(hardware);
|
||||
|
||||
static ssize_t show_nets(struct device *d,
|
||||
static ssize_t nets_show(struct device *d,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct usb_interface *intf = to_usb_interface(d);
|
||||
@ -508,7 +508,7 @@ static ssize_t show_nets(struct device *d,
|
||||
|
||||
return sprintf(buf, "%d", dev->net_count);
|
||||
}
|
||||
static DEVICE_ATTR(nets, 0444, show_nets, NULL);
|
||||
static DEVICE_ATTR_RO(nets);
|
||||
|
||||
static int esd_usb2_send_msg(struct esd_usb2 *dev, struct esd_usb2_msg *msg)
|
||||
{
|
||||
|
@ -355,7 +355,7 @@ static int es581_4_tx_can_msg(struct es58x_priv *priv,
|
||||
return -EMSGSIZE;
|
||||
|
||||
if (priv->tx_can_msg_cnt == 0) {
|
||||
msg_len = 1; /* struct es581_4_bulk_tx_can_msg:num_can_msg */
|
||||
msg_len = sizeof(es581_4_urb_cmd->bulk_tx_can_msg.num_can_msg);
|
||||
es581_4_fill_urb_header(urb_cmd, ES581_4_CAN_COMMAND_TYPE,
|
||||
ES581_4_CMD_ID_TX_MSG,
|
||||
priv->channel_idx, msg_len);
|
||||
@ -371,8 +371,7 @@ static int es581_4_tx_can_msg(struct es58x_priv *priv,
|
||||
return ret;
|
||||
|
||||
/* Fill message contents. */
|
||||
tx_can_msg = (struct es581_4_tx_can_msg *)
|
||||
&es581_4_urb_cmd->bulk_tx_can_msg.tx_can_msg_buf[msg_len - 1];
|
||||
tx_can_msg = (typeof(tx_can_msg))&es581_4_urb_cmd->raw_msg[msg_len];
|
||||
put_unaligned_le32(es58x_get_raw_can_id(cf), &tx_can_msg->can_id);
|
||||
put_unaligned_le32(priv->tx_head, &tx_can_msg->packet_idx);
|
||||
put_unaligned_le16((u16)es58x_get_flags(skb), &tx_can_msg->flags);
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "es58x_core.h"
|
||||
|
||||
#define DRV_VERSION "1.00"
|
||||
MODULE_AUTHOR("Mailhol Vincent <mailhol.vincent@wanadoo.fr>");
|
||||
MODULE_AUTHOR("Vincent Mailhol <mailhol.vincent@wanadoo.fr>");
|
||||
MODULE_AUTHOR("Arunachalam Santhanam <arunachalam.santhanam@in.bosch.com>");
|
||||
MODULE_DESCRIPTION("Socket CAN driver for ETAS ES58X USB adapters");
|
||||
MODULE_VERSION(DRV_VERSION);
|
||||
@ -70,7 +70,7 @@ MODULE_DEVICE_TABLE(usb, es58x_id_table);
|
||||
* bytes (the start of frame) are skipped and the CRC calculation
|
||||
* starts on the third byte.
|
||||
*/
|
||||
#define ES58X_CRC_CALC_OFFSET 2
|
||||
#define ES58X_CRC_CALC_OFFSET sizeof_field(union es58x_urb_cmd, sof)
|
||||
|
||||
/**
|
||||
* es58x_calculate_crc() - Compute the crc16 of a given URB.
|
||||
@ -2107,6 +2107,25 @@ static int es58x_init_netdev(struct es58x_device *es58x_dev, int channel_idx)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* es58x_free_netdevs() - Release all network resources of the device.
|
||||
* @es58x_dev: ES58X device.
|
||||
*/
|
||||
static void es58x_free_netdevs(struct es58x_device *es58x_dev)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < es58x_dev->num_can_ch; i++) {
|
||||
struct net_device *netdev = es58x_dev->netdev[i];
|
||||
|
||||
if (!netdev)
|
||||
continue;
|
||||
unregister_candev(netdev);
|
||||
es58x_dev->netdev[i] = NULL;
|
||||
free_candev(netdev);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* es58x_get_product_info() - Get the product information and print them.
|
||||
* @es58x_dev: ES58X device.
|
||||
@ -2152,14 +2171,13 @@ static int es58x_get_product_info(struct es58x_device *es58x_dev)
|
||||
/**
|
||||
* es58x_init_es58x_dev() - Initialize the ES58X device.
|
||||
* @intf: USB interface.
|
||||
* @p_es58x_dev: pointer to the address of the ES58X device.
|
||||
* @driver_info: Quirks of the device.
|
||||
*
|
||||
* Return: zero on success, errno when any error occurs.
|
||||
* Return: pointer to an ES58X device on success, error pointer when
|
||||
* any error occurs.
|
||||
*/
|
||||
static int es58x_init_es58x_dev(struct usb_interface *intf,
|
||||
struct es58x_device **p_es58x_dev,
|
||||
kernel_ulong_t driver_info)
|
||||
static struct es58x_device *es58x_init_es58x_dev(struct usb_interface *intf,
|
||||
kernel_ulong_t driver_info)
|
||||
{
|
||||
struct device *dev = &intf->dev;
|
||||
struct es58x_device *es58x_dev;
|
||||
@ -2176,7 +2194,7 @@ static int es58x_init_es58x_dev(struct usb_interface *intf,
|
||||
ret = usb_find_common_endpoints(intf->cur_altsetting, &ep_in, &ep_out,
|
||||
NULL, NULL);
|
||||
if (ret)
|
||||
return ret;
|
||||
return ERR_PTR(ret);
|
||||
|
||||
if (driver_info & ES58X_FD_FAMILY) {
|
||||
param = &es58x_fd_param;
|
||||
@ -2186,9 +2204,10 @@ static int es58x_init_es58x_dev(struct usb_interface *intf,
|
||||
ops = &es581_4_ops;
|
||||
}
|
||||
|
||||
es58x_dev = kzalloc(es58x_sizeof_es58x_device(param), GFP_KERNEL);
|
||||
es58x_dev = devm_kzalloc(dev, es58x_sizeof_es58x_device(param),
|
||||
GFP_KERNEL);
|
||||
if (!es58x_dev)
|
||||
return -ENOMEM;
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
es58x_dev->param = param;
|
||||
es58x_dev->ops = ops;
|
||||
@ -2213,9 +2232,7 @@ static int es58x_init_es58x_dev(struct usb_interface *intf,
|
||||
ep_out->bEndpointAddress);
|
||||
es58x_dev->rx_max_packet_size = le16_to_cpu(ep_in->wMaxPacketSize);
|
||||
|
||||
*p_es58x_dev = es58x_dev;
|
||||
|
||||
return 0;
|
||||
return es58x_dev;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -2232,30 +2249,21 @@ static int es58x_probe(struct usb_interface *intf,
|
||||
struct es58x_device *es58x_dev;
|
||||
int ch_idx, ret;
|
||||
|
||||
ret = es58x_init_es58x_dev(intf, &es58x_dev, id->driver_info);
|
||||
if (ret)
|
||||
return ret;
|
||||
es58x_dev = es58x_init_es58x_dev(intf, id->driver_info);
|
||||
if (IS_ERR(es58x_dev))
|
||||
return PTR_ERR(es58x_dev);
|
||||
|
||||
ret = es58x_get_product_info(es58x_dev);
|
||||
if (ret)
|
||||
goto cleanup_es58x_dev;
|
||||
return ret;
|
||||
|
||||
for (ch_idx = 0; ch_idx < es58x_dev->num_can_ch; ch_idx++) {
|
||||
ret = es58x_init_netdev(es58x_dev, ch_idx);
|
||||
if (ret)
|
||||
goto cleanup_candev;
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
cleanup_candev:
|
||||
for (ch_idx = 0; ch_idx < es58x_dev->num_can_ch; ch_idx++)
|
||||
if (es58x_dev->netdev[ch_idx]) {
|
||||
unregister_candev(es58x_dev->netdev[ch_idx]);
|
||||
free_candev(es58x_dev->netdev[ch_idx]);
|
||||
if (ret) {
|
||||
es58x_free_netdevs(es58x_dev);
|
||||
return ret;
|
||||
}
|
||||
cleanup_es58x_dev:
|
||||
kfree(es58x_dev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -2270,24 +2278,12 @@ static int es58x_probe(struct usb_interface *intf,
|
||||
static void es58x_disconnect(struct usb_interface *intf)
|
||||
{
|
||||
struct es58x_device *es58x_dev = usb_get_intfdata(intf);
|
||||
struct net_device *netdev;
|
||||
int i;
|
||||
|
||||
dev_info(&intf->dev, "Disconnecting %s %s\n",
|
||||
es58x_dev->udev->manufacturer, es58x_dev->udev->product);
|
||||
|
||||
for (i = 0; i < es58x_dev->num_can_ch; i++) {
|
||||
netdev = es58x_dev->netdev[i];
|
||||
if (!netdev)
|
||||
continue;
|
||||
unregister_candev(netdev);
|
||||
es58x_dev->netdev[i] = NULL;
|
||||
free_candev(netdev);
|
||||
}
|
||||
|
||||
es58x_free_netdevs(es58x_dev);
|
||||
es58x_free_urbs(es58x_dev);
|
||||
|
||||
kfree(es58x_dev);
|
||||
usb_set_intfdata(intf, NULL);
|
||||
}
|
||||
|
||||
|
@ -287,7 +287,7 @@ struct es58x_priv {
|
||||
* @rx_urb_cmd_max_len: Maximum length of a RX URB command.
|
||||
* @fifo_mask: Bit mask to quickly convert the tx_tail and tx_head
|
||||
* field of the struct es58x_priv into echo_skb
|
||||
* indexes. Properties: @fifo_mask = echos_skb_max - 1 where
|
||||
* indexes. Properties: @fifo_mask = echo_skb_max - 1 where
|
||||
* echo_skb_max must be a power of two. Also, echo_skb_max must
|
||||
* not exceed the maximum size of the device internal TX FIFO
|
||||
* length. This parameter is used to control the network queue
|
||||
|
@ -357,8 +357,7 @@ static int es58x_fd_tx_can_msg(struct es58x_priv *priv,
|
||||
return ret;
|
||||
|
||||
/* Fill message contents. */
|
||||
tx_can_msg = (struct es58x_fd_tx_can_msg *)
|
||||
&es58x_fd_urb_cmd->tx_can_msg_buf[msg_len];
|
||||
tx_can_msg = (typeof(tx_can_msg))&es58x_fd_urb_cmd->raw_msg[msg_len];
|
||||
tx_can_msg->packet_idx = (u8)priv->tx_head;
|
||||
put_unaligned_le32(es58x_get_raw_can_id(cf), &tx_can_msg->can_id);
|
||||
tx_can_msg->flags = (u8)es58x_get_flags(skb);
|
||||
@ -463,9 +462,9 @@ static int es58x_fd_get_timestamp(struct es58x_device *es58x_dev)
|
||||
}
|
||||
|
||||
/* Nominal bittiming constants for ES582.1 and ES584.1 as specified in
|
||||
* the microcontroller datasheet: "SAM E701/S70/V70/V71 Family"
|
||||
* section 49.6.8 "MCAN Nominal Bit Timing and Prescaler Register"
|
||||
* from Microchip.
|
||||
* the microcontroller datasheet: "SAM E70/S70/V70/V71 Family" section
|
||||
* 49.6.8 "MCAN Nominal Bit Timing and Prescaler Register" from
|
||||
* Microchip.
|
||||
*
|
||||
* The values from the specification are the hardware register
|
||||
* values. To convert them to the functional values, all ranges were
|
||||
@ -484,8 +483,8 @@ static const struct can_bittiming_const es58x_fd_nom_bittiming_const = {
|
||||
};
|
||||
|
||||
/* Data bittiming constants for ES582.1 and ES584.1 as specified in
|
||||
* the microcontroller datasheet: "SAM E701/S70/V70/V71 Family"
|
||||
* section 49.6.4 "MCAN Data Bit Timing and Prescaler Register" from
|
||||
* the microcontroller datasheet: "SAM E70/S70/V70/V71 Family" section
|
||||
* 49.6.4 "MCAN Data Bit Timing and Prescaler Register" from
|
||||
* Microchip.
|
||||
*/
|
||||
static const struct can_bittiming_const es58x_fd_data_bittiming_const = {
|
||||
@ -501,9 +500,9 @@ static const struct can_bittiming_const es58x_fd_data_bittiming_const = {
|
||||
};
|
||||
|
||||
/* Transmission Delay Compensation constants for ES582.1 and ES584.1
|
||||
* as specified in the microcontroller datasheet: "SAM
|
||||
* E701/S70/V70/V71 Family" section 49.6.15 "MCAN Transmitter Delay
|
||||
* Compensation Register" from Microchip.
|
||||
* as specified in the microcontroller datasheet: "SAM E70/S70/V70/V71
|
||||
* Family" section 49.6.15 "MCAN Transmitter Delay Compensation
|
||||
* Register" from Microchip.
|
||||
*/
|
||||
static const struct can_tdc_const es58x_tdc_const = {
|
||||
.tdcv_max = 0, /* Manual mode not supported. */
|
||||
|
@ -63,6 +63,8 @@
|
||||
|
||||
#define PCAN_USB_MSG_HEADER_LEN 2
|
||||
|
||||
#define PCAN_USB_MSG_TX_CAN 2 /* Tx msg is a CAN frame */
|
||||
|
||||
/* PCAN-USB adapter internal clock (MHz) */
|
||||
#define PCAN_USB_CRYSTAL_HZ 16000000
|
||||
|
||||
@ -73,6 +75,10 @@
|
||||
#define PCAN_USB_STATUSLEN_RTR (1 << 4)
|
||||
#define PCAN_USB_STATUSLEN_DLC (0xf)
|
||||
|
||||
/* PCAN-USB 4.1 CAN Id tx extended flags */
|
||||
#define PCAN_USB_TX_SRR 0x01 /* SJA1000 SRR command */
|
||||
#define PCAN_USB_TX_AT 0x02 /* SJA1000 AT command */
|
||||
|
||||
/* PCAN-USB error flags */
|
||||
#define PCAN_USB_ERROR_TXFULL 0x01
|
||||
#define PCAN_USB_ERROR_RXQOVR 0x02
|
||||
@ -384,7 +390,8 @@ static int pcan_usb_get_device_id(struct peak_usb_device *dev, u32 *device_id)
|
||||
if (err)
|
||||
netdev_err(dev->netdev, "getting device id failure: %d\n", err);
|
||||
|
||||
*device_id = args[0];
|
||||
else
|
||||
*device_id = args[0];
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -445,145 +452,65 @@ static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n,
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct can_frame *cf;
|
||||
enum can_state new_state;
|
||||
enum can_state new_state = CAN_STATE_ERROR_ACTIVE;
|
||||
|
||||
/* ignore this error until 1st ts received */
|
||||
if (n == PCAN_USB_ERROR_QOVR)
|
||||
if (!mc->pdev->time_ref.tick_count)
|
||||
return 0;
|
||||
|
||||
new_state = mc->pdev->dev.can.state;
|
||||
|
||||
switch (mc->pdev->dev.can.state) {
|
||||
case CAN_STATE_ERROR_ACTIVE:
|
||||
if (n & PCAN_USB_ERROR_BUS_LIGHT) {
|
||||
new_state = CAN_STATE_ERROR_WARNING;
|
||||
break;
|
||||
}
|
||||
fallthrough;
|
||||
|
||||
case CAN_STATE_ERROR_WARNING:
|
||||
if (n & PCAN_USB_ERROR_BUS_HEAVY) {
|
||||
new_state = CAN_STATE_ERROR_PASSIVE;
|
||||
break;
|
||||
}
|
||||
if (n & PCAN_USB_ERROR_BUS_OFF) {
|
||||
new_state = CAN_STATE_BUS_OFF;
|
||||
break;
|
||||
}
|
||||
if (n & ~PCAN_USB_ERROR_BUS) {
|
||||
/*
|
||||
* trick to bypass next comparison and process other
|
||||
* errors
|
||||
*/
|
||||
new_state = CAN_STATE_MAX;
|
||||
break;
|
||||
}
|
||||
if ((n & PCAN_USB_ERROR_BUS_LIGHT) == 0) {
|
||||
/* no error (back to active state) */
|
||||
new_state = CAN_STATE_ERROR_ACTIVE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case CAN_STATE_ERROR_PASSIVE:
|
||||
if (n & PCAN_USB_ERROR_BUS_OFF) {
|
||||
new_state = CAN_STATE_BUS_OFF;
|
||||
break;
|
||||
}
|
||||
if (n & PCAN_USB_ERROR_BUS_LIGHT) {
|
||||
new_state = CAN_STATE_ERROR_WARNING;
|
||||
break;
|
||||
}
|
||||
if (n & ~PCAN_USB_ERROR_BUS) {
|
||||
/*
|
||||
* trick to bypass next comparison and process other
|
||||
* errors
|
||||
*/
|
||||
new_state = CAN_STATE_MAX;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((n & PCAN_USB_ERROR_BUS_HEAVY) == 0) {
|
||||
/* no error (back to warning state) */
|
||||
new_state = CAN_STATE_ERROR_WARNING;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
/* do nothing waiting for restart */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* donot post any error if current state didn't change */
|
||||
if (mc->pdev->dev.can.state == new_state)
|
||||
return 0;
|
||||
|
||||
/* allocate an skb to store the error frame */
|
||||
skb = alloc_can_err_skb(mc->netdev, &cf);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
switch (new_state) {
|
||||
case CAN_STATE_BUS_OFF:
|
||||
cf->can_id |= CAN_ERR_BUSOFF;
|
||||
mc->pdev->dev.can.can_stats.bus_off++;
|
||||
can_bus_off(mc->netdev);
|
||||
break;
|
||||
|
||||
case CAN_STATE_ERROR_PASSIVE:
|
||||
cf->can_id |= CAN_ERR_CRTL;
|
||||
cf->data[1] = (mc->pdev->bec.txerr > mc->pdev->bec.rxerr) ?
|
||||
CAN_ERR_CRTL_TX_PASSIVE :
|
||||
CAN_ERR_CRTL_RX_PASSIVE;
|
||||
cf->data[6] = mc->pdev->bec.txerr;
|
||||
cf->data[7] = mc->pdev->bec.rxerr;
|
||||
|
||||
mc->pdev->dev.can.can_stats.error_passive++;
|
||||
break;
|
||||
|
||||
case CAN_STATE_ERROR_WARNING:
|
||||
cf->can_id |= CAN_ERR_CRTL;
|
||||
cf->data[1] = (mc->pdev->bec.txerr > mc->pdev->bec.rxerr) ?
|
||||
CAN_ERR_CRTL_TX_WARNING :
|
||||
CAN_ERR_CRTL_RX_WARNING;
|
||||
cf->data[6] = mc->pdev->bec.txerr;
|
||||
cf->data[7] = mc->pdev->bec.rxerr;
|
||||
|
||||
mc->pdev->dev.can.can_stats.error_warning++;
|
||||
break;
|
||||
|
||||
case CAN_STATE_ERROR_ACTIVE:
|
||||
cf->can_id |= CAN_ERR_CRTL;
|
||||
cf->data[1] = CAN_ERR_CRTL_ACTIVE;
|
||||
|
||||
/* sync local copies of rxerr/txerr counters */
|
||||
mc->pdev->bec.txerr = 0;
|
||||
mc->pdev->bec.rxerr = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
/* CAN_STATE_MAX (trick to handle other errors) */
|
||||
if (n & PCAN_USB_ERROR_TXQFULL)
|
||||
netdev_dbg(mc->netdev, "device Tx queue full)\n");
|
||||
|
||||
if (n & PCAN_USB_ERROR_RXQOVR) {
|
||||
netdev_dbg(mc->netdev, "data overrun interrupt\n");
|
||||
if (n & PCAN_USB_ERROR_RXQOVR) {
|
||||
/* data overrun interrupt */
|
||||
netdev_dbg(mc->netdev, "data overrun interrupt\n");
|
||||
mc->netdev->stats.rx_over_errors++;
|
||||
mc->netdev->stats.rx_errors++;
|
||||
if (cf) {
|
||||
cf->can_id |= CAN_ERR_CRTL;
|
||||
cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
|
||||
mc->netdev->stats.rx_over_errors++;
|
||||
mc->netdev->stats.rx_errors++;
|
||||
}
|
||||
|
||||
cf->data[6] = mc->pdev->bec.txerr;
|
||||
cf->data[7] = mc->pdev->bec.rxerr;
|
||||
|
||||
new_state = mc->pdev->dev.can.state;
|
||||
break;
|
||||
}
|
||||
|
||||
mc->pdev->dev.can.state = new_state;
|
||||
if (n & PCAN_USB_ERROR_TXQFULL)
|
||||
netdev_dbg(mc->netdev, "device Tx queue full)\n");
|
||||
|
||||
if (n & PCAN_USB_ERROR_BUS_OFF) {
|
||||
new_state = CAN_STATE_BUS_OFF;
|
||||
} else if (n & PCAN_USB_ERROR_BUS_HEAVY) {
|
||||
new_state = ((mc->pdev->bec.txerr >= 128) ||
|
||||
(mc->pdev->bec.rxerr >= 128)) ?
|
||||
CAN_STATE_ERROR_PASSIVE :
|
||||
CAN_STATE_ERROR_WARNING;
|
||||
} else {
|
||||
new_state = CAN_STATE_ERROR_ACTIVE;
|
||||
}
|
||||
|
||||
/* handle change of state */
|
||||
if (new_state != mc->pdev->dev.can.state) {
|
||||
enum can_state tx_state =
|
||||
(mc->pdev->bec.txerr >= mc->pdev->bec.rxerr) ?
|
||||
new_state : 0;
|
||||
enum can_state rx_state =
|
||||
(mc->pdev->bec.txerr <= mc->pdev->bec.rxerr) ?
|
||||
new_state : 0;
|
||||
|
||||
can_change_state(mc->netdev, cf, tx_state, rx_state);
|
||||
|
||||
if (new_state == CAN_STATE_BUS_OFF) {
|
||||
can_bus_off(mc->netdev);
|
||||
} else if (cf && (cf->can_id & CAN_ERR_CRTL)) {
|
||||
/* Supply TX/RX error counters in case of
|
||||
* controller error.
|
||||
*/
|
||||
cf->data[6] = mc->pdev->bec.txerr;
|
||||
cf->data[7] = mc->pdev->bec.rxerr;
|
||||
}
|
||||
}
|
||||
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
if (status_len & PCAN_USB_STATUSLEN_TIMESTAMP) {
|
||||
struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb);
|
||||
@ -704,6 +631,7 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len)
|
||||
struct sk_buff *skb;
|
||||
struct can_frame *cf;
|
||||
struct skb_shared_hwtstamps *hwts;
|
||||
u32 can_id_flags;
|
||||
|
||||
skb = alloc_can_skb(mc->netdev, &cf);
|
||||
if (!skb)
|
||||
@ -713,13 +641,15 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len)
|
||||
if ((mc->ptr + 4) > mc->end)
|
||||
goto decode_failed;
|
||||
|
||||
cf->can_id = get_unaligned_le32(mc->ptr) >> 3 | CAN_EFF_FLAG;
|
||||
can_id_flags = get_unaligned_le32(mc->ptr);
|
||||
cf->can_id = can_id_flags >> 3 | CAN_EFF_FLAG;
|
||||
mc->ptr += 4;
|
||||
} else {
|
||||
if ((mc->ptr + 2) > mc->end)
|
||||
goto decode_failed;
|
||||
|
||||
cf->can_id = get_unaligned_le16(mc->ptr) >> 5;
|
||||
can_id_flags = get_unaligned_le16(mc->ptr);
|
||||
cf->can_id = can_id_flags >> 5;
|
||||
mc->ptr += 2;
|
||||
}
|
||||
|
||||
@ -742,6 +672,10 @@ static int pcan_usb_decode_data(struct pcan_usb_msg_context *mc, u8 status_len)
|
||||
|
||||
memcpy(cf->data, mc->ptr, cf->len);
|
||||
mc->ptr += rec_len;
|
||||
|
||||
/* Ignore next byte (client private id) if SRR bit is set */
|
||||
if (can_id_flags & PCAN_USB_TX_SRR)
|
||||
mc->ptr++;
|
||||
}
|
||||
|
||||
/* convert timestamp into kernel time */
|
||||
@ -819,10 +753,11 @@ static int pcan_usb_encode_msg(struct peak_usb_device *dev, struct sk_buff *skb,
|
||||
struct net_device *netdev = dev->netdev;
|
||||
struct net_device_stats *stats = &netdev->stats;
|
||||
struct can_frame *cf = (struct can_frame *)skb->data;
|
||||
u32 can_id_flags = cf->can_id & CAN_ERR_MASK;
|
||||
u8 *pc;
|
||||
|
||||
obuf[0] = 2;
|
||||
obuf[1] = 1;
|
||||
obuf[0] = PCAN_USB_MSG_TX_CAN;
|
||||
obuf[1] = 1; /* only one CAN frame is stored in the packet */
|
||||
|
||||
pc = obuf + PCAN_USB_MSG_HEADER_LEN;
|
||||
|
||||
@ -837,12 +772,28 @@ static int pcan_usb_encode_msg(struct peak_usb_device *dev, struct sk_buff *skb,
|
||||
*pc |= PCAN_USB_STATUSLEN_EXT_ID;
|
||||
pc++;
|
||||
|
||||
put_unaligned_le32((cf->can_id & CAN_ERR_MASK) << 3, pc);
|
||||
can_id_flags <<= 3;
|
||||
|
||||
if (dev->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
|
||||
can_id_flags |= PCAN_USB_TX_SRR;
|
||||
|
||||
if (dev->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
|
||||
can_id_flags |= PCAN_USB_TX_AT;
|
||||
|
||||
put_unaligned_le32(can_id_flags, pc);
|
||||
pc += 4;
|
||||
} else {
|
||||
pc++;
|
||||
|
||||
put_unaligned_le16((cf->can_id & CAN_ERR_MASK) << 5, pc);
|
||||
can_id_flags <<= 5;
|
||||
|
||||
if (dev->can.ctrlmode & CAN_CTRLMODE_LOOPBACK)
|
||||
can_id_flags |= PCAN_USB_TX_SRR;
|
||||
|
||||
if (dev->can.ctrlmode & CAN_CTRLMODE_ONE_SHOT)
|
||||
can_id_flags |= PCAN_USB_TX_AT;
|
||||
|
||||
put_unaligned_le16(can_id_flags, pc);
|
||||
pc += 2;
|
||||
}
|
||||
|
||||
@ -852,6 +803,10 @@ static int pcan_usb_encode_msg(struct peak_usb_device *dev, struct sk_buff *skb,
|
||||
pc += cf->len;
|
||||
}
|
||||
|
||||
/* SRR bit needs a writer id (useless here) */
|
||||
if (can_id_flags & PCAN_USB_TX_SRR)
|
||||
*pc++ = 0x80;
|
||||
|
||||
obuf[(*size)-1] = (u8)(stats->tx_packets & 0xff);
|
||||
|
||||
return 0;
|
||||
@ -926,6 +881,19 @@ static int pcan_usb_init(struct peak_usb_device *dev)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Since rev 4.1, PCAN-USB is able to make single-shot as well as
|
||||
* looped back frames.
|
||||
*/
|
||||
if (dev->device_rev >= 41) {
|
||||
struct can_priv *priv = netdev_priv(dev->netdev);
|
||||
|
||||
priv->ctrlmode_supported |= CAN_CTRLMODE_ONE_SHOT |
|
||||
CAN_CTRLMODE_LOOPBACK;
|
||||
} else {
|
||||
dev_info(dev->netdev->dev.parent,
|
||||
"Firmware update available. Please contact support@peak-system.com\n");
|
||||
}
|
||||
|
||||
dev_info(dev->netdev->dev.parent,
|
||||
"PEAK-System %s adapter hwrev %u serial %08X (%u channel)\n",
|
||||
pcan_usb.name, dev->device_rev, serial_number,
|
||||
|
@ -37,7 +37,7 @@
|
||||
* quanta, from when the bit is sent on the TX pin to when it is
|
||||
* received on the RX pin of the transmitter. Possible options:
|
||||
*
|
||||
* O: automatic mode. The controller dynamically measure @tdcv
|
||||
* 0: automatic mode. The controller dynamically measures @tdcv
|
||||
* for each transmitted CAN FD frame.
|
||||
*
|
||||
* Other values: manual mode. Use the fixed provided value.
|
||||
@ -45,7 +45,7 @@
|
||||
* @tdco: Transmitter Delay Compensation Offset. Offset value, in time
|
||||
* quanta, defining the distance between the start of the bit
|
||||
* reception on the RX pin of the transceiver and the SSP
|
||||
* position such as SSP = @tdcv + @tdco.
|
||||
* position such that SSP = @tdcv + @tdco.
|
||||
*
|
||||
* If @tdco is zero, then TDC is disabled and both @tdcv and
|
||||
* @tdcf should be ignored.
|
||||
|
23
include/linux/can/platform/flexcan.h
Normal file
23
include/linux/can/platform/flexcan.h
Normal file
@ -0,0 +1,23 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2021 Angelo Dureghello <angelo@kernel-space.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef _CAN_PLATFORM_FLEXCAN_H
|
||||
#define _CAN_PLATFORM_FLEXCAN_H
|
||||
|
||||
struct flexcan_platform_data {
|
||||
u32 clock_frequency;
|
||||
u8 clk_src;
|
||||
};
|
||||
|
||||
#endif /* _CAN_PLATFORM_FLEXCAN_H */
|
@ -20,6 +20,7 @@ struct can_rx_offload {
|
||||
bool drop);
|
||||
|
||||
struct sk_buff_head skb_queue;
|
||||
struct sk_buff_head skb_irq_queue;
|
||||
u32 skb_queue_len_max;
|
||||
|
||||
unsigned int mb_first;
|
||||
@ -48,14 +49,11 @@ unsigned int can_rx_offload_get_echo_skb(struct can_rx_offload *offload,
|
||||
unsigned int *frame_len_ptr);
|
||||
int can_rx_offload_queue_tail(struct can_rx_offload *offload,
|
||||
struct sk_buff *skb);
|
||||
void can_rx_offload_irq_finish(struct can_rx_offload *offload);
|
||||
void can_rx_offload_threaded_irq_finish(struct can_rx_offload *offload);
|
||||
void can_rx_offload_del(struct can_rx_offload *offload);
|
||||
void can_rx_offload_enable(struct can_rx_offload *offload);
|
||||
|
||||
static inline void can_rx_offload_schedule(struct can_rx_offload *offload)
|
||||
{
|
||||
napi_schedule(&offload->napi);
|
||||
}
|
||||
|
||||
static inline void can_rx_offload_disable(struct can_rx_offload *offload)
|
||||
{
|
||||
napi_disable(&offload->napi);
|
||||
|
@ -352,7 +352,7 @@ static void j1939_sk_sock_destruct(struct sock *sk)
|
||||
{
|
||||
struct j1939_sock *jsk = j1939_sk(sk);
|
||||
|
||||
/* This function will be call by the generic networking code, when then
|
||||
/* This function will be called by the generic networking code, when
|
||||
* the socket is ultimately closed (sk->sk_destruct).
|
||||
*
|
||||
* The race between
|
||||
|
@ -776,7 +776,7 @@ static int j1939_session_tx_dpo(struct j1939_session *session)
|
||||
static int j1939_session_tx_dat(struct j1939_session *session)
|
||||
{
|
||||
struct j1939_priv *priv = session->priv;
|
||||
struct j1939_sk_buff_cb *skcb;
|
||||
struct j1939_sk_buff_cb *se_skcb;
|
||||
int offset, pkt_done, pkt_end;
|
||||
unsigned int len, pdelay;
|
||||
struct sk_buff *se_skb;
|
||||
@ -788,7 +788,7 @@ static int j1939_session_tx_dat(struct j1939_session *session)
|
||||
if (!se_skb)
|
||||
return -ENOBUFS;
|
||||
|
||||
skcb = j1939_skb_to_cb(se_skb);
|
||||
se_skcb = j1939_skb_to_cb(se_skb);
|
||||
tpdat = se_skb->data;
|
||||
ret = 0;
|
||||
pkt_done = 0;
|
||||
@ -800,7 +800,7 @@ static int j1939_session_tx_dat(struct j1939_session *session)
|
||||
|
||||
while (session->pkt.tx < pkt_end) {
|
||||
dat[0] = session->pkt.tx - session->pkt.dpo + 1;
|
||||
offset = (session->pkt.tx * 7) - skcb->offset;
|
||||
offset = (session->pkt.tx * 7) - se_skcb->offset;
|
||||
len = se_skb->len - offset;
|
||||
if (len > 7)
|
||||
len = 7;
|
||||
@ -808,7 +808,8 @@ static int j1939_session_tx_dat(struct j1939_session *session)
|
||||
if (offset + len > se_skb->len) {
|
||||
netdev_err_once(priv->ndev,
|
||||
"%s: 0x%p: requested data outside of queued buffer: offset %i, len %i, pkt.tx: %i\n",
|
||||
__func__, session, skcb->offset, se_skb->len , session->pkt.tx);
|
||||
__func__, session, se_skcb->offset,
|
||||
se_skb->len , session->pkt.tx);
|
||||
ret = -EOVERFLOW;
|
||||
goto out_free;
|
||||
}
|
||||
@ -1092,7 +1093,7 @@ j1939_session_deactivate_activate_next(struct j1939_session *session)
|
||||
}
|
||||
|
||||
static void __j1939_session_cancel(struct j1939_session *session,
|
||||
enum j1939_xtp_abort err)
|
||||
enum j1939_xtp_abort err)
|
||||
{
|
||||
struct j1939_priv *priv = session->priv;
|
||||
|
||||
@ -1190,13 +1191,13 @@ static enum hrtimer_restart j1939_tp_txtimer(struct hrtimer *hrtimer)
|
||||
|
||||
static void j1939_session_completed(struct j1939_session *session)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct sk_buff *se_skb;
|
||||
|
||||
if (!session->transmission) {
|
||||
skb = j1939_session_skb_get(session);
|
||||
se_skb = j1939_session_skb_get(session);
|
||||
/* distribute among j1939 receivers */
|
||||
j1939_sk_recv(session->priv, skb);
|
||||
consume_skb(skb);
|
||||
j1939_sk_recv(session->priv, se_skb);
|
||||
consume_skb(se_skb);
|
||||
}
|
||||
|
||||
j1939_session_deactivate_activate_next(session);
|
||||
@ -1263,12 +1264,14 @@ static bool j1939_xtp_rx_cmd_bad_pgn(struct j1939_session *session,
|
||||
break;
|
||||
|
||||
case J1939_ETP_CMD_RTS:
|
||||
case J1939_TP_CMD_RTS: /* fall through */
|
||||
fallthrough;
|
||||
case J1939_TP_CMD_RTS:
|
||||
abort = J1939_XTP_ABORT_BUSY;
|
||||
break;
|
||||
|
||||
case J1939_ETP_CMD_CTS:
|
||||
case J1939_TP_CMD_CTS: /* fall through */
|
||||
fallthrough;
|
||||
case J1939_TP_CMD_CTS:
|
||||
abort = J1939_XTP_ABORT_ECTS_UNXPECTED_PGN;
|
||||
break;
|
||||
|
||||
@ -1277,7 +1280,8 @@ static bool j1939_xtp_rx_cmd_bad_pgn(struct j1939_session *session,
|
||||
break;
|
||||
|
||||
case J1939_ETP_CMD_EOMA:
|
||||
case J1939_TP_CMD_EOMA: /* fall through */
|
||||
fallthrough;
|
||||
case J1939_TP_CMD_EOMA:
|
||||
abort = J1939_XTP_ABORT_OTHER;
|
||||
break;
|
||||
|
||||
@ -1767,7 +1771,7 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct j1939_priv *priv = session->priv;
|
||||
struct j1939_sk_buff_cb *skcb;
|
||||
struct j1939_sk_buff_cb *skcb, *se_skcb;
|
||||
struct sk_buff *se_skb = NULL;
|
||||
const u8 *dat;
|
||||
u8 *tpdat;
|
||||
@ -1792,7 +1796,8 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session,
|
||||
break;
|
||||
fallthrough;
|
||||
case J1939_TP_CMD_BAM:
|
||||
case J1939_TP_CMD_CTS: /* fall through */
|
||||
fallthrough;
|
||||
case J1939_TP_CMD_CTS:
|
||||
if (skcb->addr.type != J1939_ETP)
|
||||
break;
|
||||
fallthrough;
|
||||
@ -1817,8 +1822,8 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session,
|
||||
goto out_session_cancel;
|
||||
}
|
||||
|
||||
skcb = j1939_skb_to_cb(se_skb);
|
||||
offset = packet * 7 - skcb->offset;
|
||||
se_skcb = j1939_skb_to_cb(se_skb);
|
||||
offset = packet * 7 - se_skcb->offset;
|
||||
nbytes = se_skb->len - offset;
|
||||
if (nbytes > 7)
|
||||
nbytes = 7;
|
||||
@ -1846,7 +1851,7 @@ static void j1939_xtp_rx_dat_one(struct j1939_session *session,
|
||||
if (packet == session->pkt.rx)
|
||||
session->pkt.rx++;
|
||||
|
||||
if (skcb->addr.type != J1939_ETP &&
|
||||
if (se_skcb->addr.type != J1939_ETP &&
|
||||
j1939_cb_is_broadcast(&session->skcb)) {
|
||||
if (session->pkt.rx >= session->pkt.total)
|
||||
final = true;
|
||||
@ -1995,7 +2000,8 @@ static void j1939_tp_cmd_recv(struct j1939_priv *priv, struct sk_buff *skb)
|
||||
extd = J1939_ETP;
|
||||
fallthrough;
|
||||
case J1939_TP_CMD_BAM:
|
||||
case J1939_TP_CMD_RTS: /* fall through */
|
||||
fallthrough;
|
||||
case J1939_TP_CMD_RTS:
|
||||
if (skcb->addr.type != extd)
|
||||
return;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user