Commit 9c0532f9 authored by David S. Miller's avatar David S. Miller

Merge tag 'linux-can-next-for-5.15-20210804' of...

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

Marc Kleine-Budde says:

====================
pull-request: can-next 2021-08-04

this is a pull request of 5 patches for net-next/master.

The first patch is by me and fixes a typo in a comment in the CAN
J1939 protocol.

The next 2 patches are by Oleksij Rempel and update the CAN J1939
protocol to send RX status updates via the error queue mechanism.

The next patch is by me and adds a missing variable initialization to
the flexcan driver (the problem was introduced in the current net-next
cycle).

The last patch is by Aswath Govindraju and adds power-domains to the
Bosch m_can DT binding documentation.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 51b8f812 d85165b2
...@@ -104,6 +104,12 @@ properties: ...@@ -104,6 +104,12 @@ properties:
maximum: 32 maximum: 32
maxItems: 1 maxItems: 1
power-domains:
description:
Power domain provider node and an args specifier containing
the can device id value.
maxItems: 1
can-transceiver: can-transceiver:
$ref: can-transceiver.yaml# $ref: can-transceiver.yaml#
......
...@@ -649,7 +649,7 @@ static inline void flexcan_error_irq_disable(const struct flexcan_priv *priv) ...@@ -649,7 +649,7 @@ static inline void flexcan_error_irq_disable(const struct flexcan_priv *priv)
static int flexcan_clks_enable(const struct flexcan_priv *priv) static int flexcan_clks_enable(const struct flexcan_priv *priv)
{ {
int err; int err = 0;
if (priv->clk_ipg) { if (priv->clk_ipg) {
err = clk_prepare_enable(priv->clk_ipg); err = clk_prepare_enable(priv->clk_ipg);
......
...@@ -78,11 +78,20 @@ enum { ...@@ -78,11 +78,20 @@ enum {
enum { enum {
J1939_NLA_PAD, J1939_NLA_PAD,
J1939_NLA_BYTES_ACKED, J1939_NLA_BYTES_ACKED,
J1939_NLA_TOTAL_SIZE,
J1939_NLA_PGN,
J1939_NLA_SRC_NAME,
J1939_NLA_DEST_NAME,
J1939_NLA_SRC_ADDR,
J1939_NLA_DEST_ADDR,
}; };
enum { enum {
J1939_EE_INFO_NONE, J1939_EE_INFO_NONE,
J1939_EE_INFO_TX_ABORT, J1939_EE_INFO_TX_ABORT,
J1939_EE_INFO_RX_RTS,
J1939_EE_INFO_RX_DPO,
J1939_EE_INFO_RX_ABORT,
}; };
struct j1939_filter { struct j1939_filter {
......
...@@ -20,9 +20,12 @@ ...@@ -20,9 +20,12 @@
struct j1939_session; struct j1939_session;
enum j1939_sk_errqueue_type { enum j1939_sk_errqueue_type {
J1939_ERRQUEUE_ACK, J1939_ERRQUEUE_TX_ACK,
J1939_ERRQUEUE_SCHED, J1939_ERRQUEUE_TX_SCHED,
J1939_ERRQUEUE_ABORT, J1939_ERRQUEUE_TX_ABORT,
J1939_ERRQUEUE_RX_RTS,
J1939_ERRQUEUE_RX_DPO,
J1939_ERRQUEUE_RX_ABORT,
}; };
/* j1939 devices */ /* j1939 devices */
...@@ -87,6 +90,7 @@ struct j1939_priv { ...@@ -87,6 +90,7 @@ struct j1939_priv {
struct list_head j1939_socks; struct list_head j1939_socks;
struct kref rx_kref; struct kref rx_kref;
u32 rx_tskey;
}; };
void j1939_ecu_put(struct j1939_ecu *ecu); void j1939_ecu_put(struct j1939_ecu *ecu);
......
...@@ -905,20 +905,33 @@ static struct sk_buff *j1939_sk_alloc_skb(struct net_device *ndev, ...@@ -905,20 +905,33 @@ static struct sk_buff *j1939_sk_alloc_skb(struct net_device *ndev,
return NULL; return NULL;
} }
static size_t j1939_sk_opt_stats_get_size(void) static size_t j1939_sk_opt_stats_get_size(enum j1939_sk_errqueue_type type)
{ {
return switch (type) {
nla_total_size(sizeof(u32)) + /* J1939_NLA_BYTES_ACKED */ case J1939_ERRQUEUE_RX_RTS:
0; return
nla_total_size(sizeof(u32)) + /* J1939_NLA_TOTAL_SIZE */
nla_total_size(sizeof(u32)) + /* J1939_NLA_PGN */
nla_total_size(sizeof(u64)) + /* J1939_NLA_SRC_NAME */
nla_total_size(sizeof(u64)) + /* J1939_NLA_DEST_NAME */
nla_total_size(sizeof(u8)) + /* J1939_NLA_SRC_ADDR */
nla_total_size(sizeof(u8)) + /* J1939_NLA_DEST_ADDR */
0;
default:
return
nla_total_size(sizeof(u32)) + /* J1939_NLA_BYTES_ACKED */
0;
}
} }
static struct sk_buff * static struct sk_buff *
j1939_sk_get_timestamping_opt_stats(struct j1939_session *session) j1939_sk_get_timestamping_opt_stats(struct j1939_session *session,
enum j1939_sk_errqueue_type type)
{ {
struct sk_buff *stats; struct sk_buff *stats;
u32 size; u32 size;
stats = alloc_skb(j1939_sk_opt_stats_get_size(), GFP_ATOMIC); stats = alloc_skb(j1939_sk_opt_stats_get_size(type), GFP_ATOMIC);
if (!stats) if (!stats)
return NULL; return NULL;
...@@ -928,32 +941,67 @@ j1939_sk_get_timestamping_opt_stats(struct j1939_session *session) ...@@ -928,32 +941,67 @@ j1939_sk_get_timestamping_opt_stats(struct j1939_session *session)
size = min(session->pkt.tx_acked * 7, size = min(session->pkt.tx_acked * 7,
session->total_message_size); session->total_message_size);
nla_put_u32(stats, J1939_NLA_BYTES_ACKED, size); switch (type) {
case J1939_ERRQUEUE_RX_RTS:
nla_put_u32(stats, J1939_NLA_TOTAL_SIZE,
session->total_message_size);
nla_put_u32(stats, J1939_NLA_PGN,
session->skcb.addr.pgn);
nla_put_u64_64bit(stats, J1939_NLA_SRC_NAME,
session->skcb.addr.src_name, J1939_NLA_PAD);
nla_put_u64_64bit(stats, J1939_NLA_DEST_NAME,
session->skcb.addr.dst_name, J1939_NLA_PAD);
nla_put_u8(stats, J1939_NLA_SRC_ADDR,
session->skcb.addr.sa);
nla_put_u8(stats, J1939_NLA_DEST_ADDR,
session->skcb.addr.da);
break;
default:
nla_put_u32(stats, J1939_NLA_BYTES_ACKED, size);
}
return stats; return stats;
} }
void j1939_sk_errqueue(struct j1939_session *session, static void __j1939_sk_errqueue(struct j1939_session *session, struct sock *sk,
enum j1939_sk_errqueue_type type) enum j1939_sk_errqueue_type type)
{ {
struct j1939_priv *priv = session->priv; struct j1939_priv *priv = session->priv;
struct sock *sk = session->sk;
struct j1939_sock *jsk; struct j1939_sock *jsk;
struct sock_exterr_skb *serr; struct sock_exterr_skb *serr;
struct sk_buff *skb; struct sk_buff *skb;
char *state = "UNK"; char *state = "UNK";
int err; int err;
/* currently we have no sk for the RX session */
if (!sk)
return;
jsk = j1939_sk(sk); jsk = j1939_sk(sk);
if (!(jsk->state & J1939_SOCK_ERRQUEUE)) if (!(jsk->state & J1939_SOCK_ERRQUEUE))
return; return;
skb = j1939_sk_get_timestamping_opt_stats(session); switch (type) {
case J1939_ERRQUEUE_TX_ACK:
if (!(sk->sk_tsflags & SOF_TIMESTAMPING_TX_ACK))
return;
break;
case J1939_ERRQUEUE_TX_SCHED:
if (!(sk->sk_tsflags & SOF_TIMESTAMPING_TX_SCHED))
return;
break;
case J1939_ERRQUEUE_TX_ABORT:
break;
case J1939_ERRQUEUE_RX_RTS:
fallthrough;
case J1939_ERRQUEUE_RX_DPO:
fallthrough;
case J1939_ERRQUEUE_RX_ABORT:
if (!(sk->sk_tsflags & SOF_TIMESTAMPING_RX_SOFTWARE))
return;
break;
default:
netdev_err(priv->ndev, "Unknown errqueue type %i\n", type);
}
skb = j1939_sk_get_timestamping_opt_stats(session, type);
if (!skb) if (!skb)
return; return;
...@@ -964,36 +1012,42 @@ void j1939_sk_errqueue(struct j1939_session *session, ...@@ -964,36 +1012,42 @@ void j1939_sk_errqueue(struct j1939_session *session,
serr = SKB_EXT_ERR(skb); serr = SKB_EXT_ERR(skb);
memset(serr, 0, sizeof(*serr)); memset(serr, 0, sizeof(*serr));
switch (type) { switch (type) {
case J1939_ERRQUEUE_ACK: case J1939_ERRQUEUE_TX_ACK:
if (!(sk->sk_tsflags & SOF_TIMESTAMPING_TX_ACK)) {
kfree_skb(skb);
return;
}
serr->ee.ee_errno = ENOMSG; serr->ee.ee_errno = ENOMSG;
serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING; serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
serr->ee.ee_info = SCM_TSTAMP_ACK; serr->ee.ee_info = SCM_TSTAMP_ACK;
state = "ACK"; state = "TX ACK";
break; break;
case J1939_ERRQUEUE_SCHED: case J1939_ERRQUEUE_TX_SCHED:
if (!(sk->sk_tsflags & SOF_TIMESTAMPING_TX_SCHED)) {
kfree_skb(skb);
return;
}
serr->ee.ee_errno = ENOMSG; serr->ee.ee_errno = ENOMSG;
serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING; serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
serr->ee.ee_info = SCM_TSTAMP_SCHED; serr->ee.ee_info = SCM_TSTAMP_SCHED;
state = "SCH"; state = "TX SCH";
break; break;
case J1939_ERRQUEUE_ABORT: case J1939_ERRQUEUE_TX_ABORT:
serr->ee.ee_errno = session->err; serr->ee.ee_errno = session->err;
serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL; serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
serr->ee.ee_info = J1939_EE_INFO_TX_ABORT; serr->ee.ee_info = J1939_EE_INFO_TX_ABORT;
state = "ABT"; state = "TX ABT";
break;
case J1939_ERRQUEUE_RX_RTS:
serr->ee.ee_errno = ENOMSG;
serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
serr->ee.ee_info = J1939_EE_INFO_RX_RTS;
state = "RX RTS";
break;
case J1939_ERRQUEUE_RX_DPO:
serr->ee.ee_errno = ENOMSG;
serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
serr->ee.ee_info = J1939_EE_INFO_RX_DPO;
state = "RX DPO";
break;
case J1939_ERRQUEUE_RX_ABORT:
serr->ee.ee_errno = session->err;
serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
serr->ee.ee_info = J1939_EE_INFO_RX_ABORT;
state = "RX ABT";
break; break;
default:
netdev_err(priv->ndev, "Unknown errqueue type %i\n", type);
} }
serr->opt_stats = true; serr->opt_stats = true;
...@@ -1008,6 +1062,27 @@ void j1939_sk_errqueue(struct j1939_session *session, ...@@ -1008,6 +1062,27 @@ void j1939_sk_errqueue(struct j1939_session *session,
kfree_skb(skb); kfree_skb(skb);
}; };
void j1939_sk_errqueue(struct j1939_session *session,
enum j1939_sk_errqueue_type type)
{
struct j1939_priv *priv = session->priv;
struct j1939_sock *jsk;
if (session->sk) {
/* send TX notifications to the socket of origin */
__j1939_sk_errqueue(session, session->sk, type);
return;
}
/* spread RX notifications to all sockets subscribed to this session */
spin_lock_bh(&priv->j1939_socks_lock);
list_for_each_entry(jsk, &priv->j1939_socks, list) {
if (j1939_sk_recv_match_one(jsk, &session->skcb))
__j1939_sk_errqueue(session, &jsk->sk, type);
}
spin_unlock_bh(&priv->j1939_socks_lock);
};
void j1939_sk_send_loop_abort(struct sock *sk, int err) void j1939_sk_send_loop_abort(struct sock *sk, int err)
{ {
sk->sk_err = err; sk->sk_err = err;
......
...@@ -260,10 +260,14 @@ static void __j1939_session_drop(struct j1939_session *session) ...@@ -260,10 +260,14 @@ static void __j1939_session_drop(struct j1939_session *session)
static void j1939_session_destroy(struct j1939_session *session) static void j1939_session_destroy(struct j1939_session *session)
{ {
if (session->err) if (session->transmission) {
j1939_sk_errqueue(session, J1939_ERRQUEUE_ABORT); if (session->err)
else j1939_sk_errqueue(session, J1939_ERRQUEUE_TX_ABORT);
j1939_sk_errqueue(session, J1939_ERRQUEUE_ACK); else
j1939_sk_errqueue(session, J1939_ERRQUEUE_TX_ACK);
} else if (session->err) {
j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_ABORT);
}
netdev_dbg(session->priv->ndev, "%s: 0x%p\n", __func__, session); netdev_dbg(session->priv->ndev, "%s: 0x%p\n", __func__, session);
...@@ -822,7 +826,7 @@ static int j1939_session_tx_dat(struct j1939_session *session) ...@@ -822,7 +826,7 @@ static int j1939_session_tx_dat(struct j1939_session *session)
memcpy(&dat[1], &tpdat[offset], len); memcpy(&dat[1], &tpdat[offset], len);
ret = j1939_tp_tx_dat(session, dat, len + 1); ret = j1939_tp_tx_dat(session, dat, len + 1);
if (ret < 0) { if (ret < 0) {
/* ENOBUS == CAN interface TX queue is full */ /* ENOBUFS == CAN interface TX queue is full */
if (ret != -ENOBUFS) if (ret != -ENOBUFS)
netdev_alert(priv->ndev, netdev_alert(priv->ndev,
"%s: 0x%p: queue data error: %i\n", "%s: 0x%p: queue data error: %i\n",
...@@ -1044,7 +1048,7 @@ static int j1939_simple_txnext(struct j1939_session *session) ...@@ -1044,7 +1048,7 @@ static int j1939_simple_txnext(struct j1939_session *session)
if (ret) if (ret)
goto out_free; goto out_free;
j1939_sk_errqueue(session, J1939_ERRQUEUE_SCHED); j1939_sk_errqueue(session, J1939_ERRQUEUE_TX_SCHED);
j1939_sk_queue_activate_next(session); j1939_sk_queue_activate_next(session);
out_free: out_free:
...@@ -1116,6 +1120,8 @@ static void __j1939_session_cancel(struct j1939_session *session, ...@@ -1116,6 +1120,8 @@ static void __j1939_session_cancel(struct j1939_session *session,
if (session->sk) if (session->sk)
j1939_sk_send_loop_abort(session->sk, session->err); j1939_sk_send_loop_abort(session->sk, session->err);
else
j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_ABORT);
} }
static void j1939_session_cancel(struct j1939_session *session, static void j1939_session_cancel(struct j1939_session *session,
...@@ -1330,6 +1336,8 @@ static void j1939_xtp_rx_abort_one(struct j1939_priv *priv, struct sk_buff *skb, ...@@ -1330,6 +1336,8 @@ static void j1939_xtp_rx_abort_one(struct j1939_priv *priv, struct sk_buff *skb,
session->err = j1939_xtp_abort_to_errno(priv, abort); session->err = j1939_xtp_abort_to_errno(priv, abort);
if (session->sk) if (session->sk)
j1939_sk_send_loop_abort(session->sk, session->err); j1939_sk_send_loop_abort(session->sk, session->err);
else
j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_ABORT);
j1939_session_deactivate_activate_next(session); j1939_session_deactivate_activate_next(session);
abort_put: abort_put:
...@@ -1438,7 +1446,7 @@ j1939_xtp_rx_cts_one(struct j1939_session *session, struct sk_buff *skb) ...@@ -1438,7 +1446,7 @@ j1939_xtp_rx_cts_one(struct j1939_session *session, struct sk_buff *skb)
if (session->transmission) { if (session->transmission) {
if (session->pkt.tx_acked) if (session->pkt.tx_acked)
j1939_sk_errqueue(session, j1939_sk_errqueue(session,
J1939_ERRQUEUE_SCHED); J1939_ERRQUEUE_TX_SCHED);
j1939_session_txtimer_cancel(session); j1939_session_txtimer_cancel(session);
j1939_tp_schedule_txtimer(session, 0); j1939_tp_schedule_txtimer(session, 0);
} }
...@@ -1630,6 +1638,9 @@ j1939_session *j1939_xtp_rx_rts_session_new(struct j1939_priv *priv, ...@@ -1630,6 +1638,9 @@ j1939_session *j1939_xtp_rx_rts_session_new(struct j1939_priv *priv,
session->pkt.rx = 0; session->pkt.rx = 0;
session->pkt.tx = 0; session->pkt.tx = 0;
session->tskey = priv->rx_tskey++;
j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_RTS);
WARN_ON_ONCE(j1939_session_activate(session)); WARN_ON_ONCE(j1939_session_activate(session));
return session; return session;
...@@ -1752,6 +1763,9 @@ static void j1939_xtp_rx_dpo_one(struct j1939_session *session, ...@@ -1752,6 +1763,9 @@ static void j1939_xtp_rx_dpo_one(struct j1939_session *session,
session->pkt.dpo = j1939_etp_ctl_to_packet(skb->data); session->pkt.dpo = j1939_etp_ctl_to_packet(skb->data);
session->last_cmd = dat[0]; session->last_cmd = dat[0];
j1939_tp_set_rxtimeout(session, 750); j1939_tp_set_rxtimeout(session, 750);
if (!session->transmission)
j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_DPO);
} }
static void j1939_xtp_rx_dpo(struct j1939_priv *priv, struct sk_buff *skb, static void j1939_xtp_rx_dpo(struct j1939_priv *priv, struct sk_buff *skb,
......
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