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:
maximum: 32
maxItems: 1
power-domains:
description:
Power domain provider node and an args specifier containing
the can device id value.
maxItems: 1
can-transceiver:
$ref: can-transceiver.yaml#
......
......@@ -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)
{
int err;
int err = 0;
if (priv->clk_ipg) {
err = clk_prepare_enable(priv->clk_ipg);
......
......@@ -78,11 +78,20 @@ enum {
enum {
J1939_NLA_PAD,
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 {
J1939_EE_INFO_NONE,
J1939_EE_INFO_TX_ABORT,
J1939_EE_INFO_RX_RTS,
J1939_EE_INFO_RX_DPO,
J1939_EE_INFO_RX_ABORT,
};
struct j1939_filter {
......
......@@ -20,9 +20,12 @@
struct j1939_session;
enum j1939_sk_errqueue_type {
J1939_ERRQUEUE_ACK,
J1939_ERRQUEUE_SCHED,
J1939_ERRQUEUE_ABORT,
J1939_ERRQUEUE_TX_ACK,
J1939_ERRQUEUE_TX_SCHED,
J1939_ERRQUEUE_TX_ABORT,
J1939_ERRQUEUE_RX_RTS,
J1939_ERRQUEUE_RX_DPO,
J1939_ERRQUEUE_RX_ABORT,
};
/* j1939 devices */
......@@ -87,6 +90,7 @@ struct j1939_priv {
struct list_head j1939_socks;
struct kref rx_kref;
u32 rx_tskey;
};
void j1939_ecu_put(struct j1939_ecu *ecu);
......
......@@ -905,20 +905,33 @@ static struct sk_buff *j1939_sk_alloc_skb(struct net_device *ndev,
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
nla_total_size(sizeof(u32)) + /* J1939_NLA_BYTES_ACKED */
0;
switch (type) {
case J1939_ERRQUEUE_RX_RTS:
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 *
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;
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)
return NULL;
......@@ -928,32 +941,67 @@ j1939_sk_get_timestamping_opt_stats(struct j1939_session *session)
size = min(session->pkt.tx_acked * 7,
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;
}
void j1939_sk_errqueue(struct j1939_session *session,
enum j1939_sk_errqueue_type type)
static void __j1939_sk_errqueue(struct j1939_session *session, struct sock *sk,
enum j1939_sk_errqueue_type type)
{
struct j1939_priv *priv = session->priv;
struct sock *sk = session->sk;
struct j1939_sock *jsk;
struct sock_exterr_skb *serr;
struct sk_buff *skb;
char *state = "UNK";
int err;
/* currently we have no sk for the RX session */
if (!sk)
return;
jsk = j1939_sk(sk);
if (!(jsk->state & J1939_SOCK_ERRQUEUE))
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)
return;
......@@ -964,36 +1012,42 @@ void j1939_sk_errqueue(struct j1939_session *session,
serr = SKB_EXT_ERR(skb);
memset(serr, 0, sizeof(*serr));
switch (type) {
case J1939_ERRQUEUE_ACK:
if (!(sk->sk_tsflags & SOF_TIMESTAMPING_TX_ACK)) {
kfree_skb(skb);
return;
}
case J1939_ERRQUEUE_TX_ACK:
serr->ee.ee_errno = ENOMSG;
serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
serr->ee.ee_info = SCM_TSTAMP_ACK;
state = "ACK";
state = "TX ACK";
break;
case J1939_ERRQUEUE_SCHED:
if (!(sk->sk_tsflags & SOF_TIMESTAMPING_TX_SCHED)) {
kfree_skb(skb);
return;
}
case J1939_ERRQUEUE_TX_SCHED:
serr->ee.ee_errno = ENOMSG;
serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
serr->ee.ee_info = SCM_TSTAMP_SCHED;
state = "SCH";
state = "TX SCH";
break;
case J1939_ERRQUEUE_ABORT:
case J1939_ERRQUEUE_TX_ABORT:
serr->ee.ee_errno = session->err;
serr->ee.ee_origin = SO_EE_ORIGIN_LOCAL;
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;
default:
netdev_err(priv->ndev, "Unknown errqueue type %i\n", type);
}
serr->opt_stats = true;
......@@ -1008,6 +1062,27 @@ void j1939_sk_errqueue(struct j1939_session *session,
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)
{
sk->sk_err = err;
......
......@@ -260,10 +260,14 @@ static void __j1939_session_drop(struct j1939_session *session)
static void j1939_session_destroy(struct j1939_session *session)
{
if (session->err)
j1939_sk_errqueue(session, J1939_ERRQUEUE_ABORT);
else
j1939_sk_errqueue(session, J1939_ERRQUEUE_ACK);
if (session->transmission) {
if (session->err)
j1939_sk_errqueue(session, J1939_ERRQUEUE_TX_ABORT);
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);
......@@ -822,7 +826,7 @@ static int j1939_session_tx_dat(struct j1939_session *session)
memcpy(&dat[1], &tpdat[offset], len);
ret = j1939_tp_tx_dat(session, dat, len + 1);
if (ret < 0) {
/* ENOBUS == CAN interface TX queue is full */
/* ENOBUFS == CAN interface TX queue is full */
if (ret != -ENOBUFS)
netdev_alert(priv->ndev,
"%s: 0x%p: queue data error: %i\n",
......@@ -1044,7 +1048,7 @@ static int j1939_simple_txnext(struct j1939_session *session)
if (ret)
goto out_free;
j1939_sk_errqueue(session, J1939_ERRQUEUE_SCHED);
j1939_sk_errqueue(session, J1939_ERRQUEUE_TX_SCHED);
j1939_sk_queue_activate_next(session);
out_free:
......@@ -1116,6 +1120,8 @@ static void __j1939_session_cancel(struct j1939_session *session,
if (session->sk)
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,
......@@ -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);
if (session->sk)
j1939_sk_send_loop_abort(session->sk, session->err);
else
j1939_sk_errqueue(session, J1939_ERRQUEUE_RX_ABORT);
j1939_session_deactivate_activate_next(session);
abort_put:
......@@ -1438,7 +1446,7 @@ j1939_xtp_rx_cts_one(struct j1939_session *session, struct sk_buff *skb)
if (session->transmission) {
if (session->pkt.tx_acked)
j1939_sk_errqueue(session,
J1939_ERRQUEUE_SCHED);
J1939_ERRQUEUE_TX_SCHED);
j1939_session_txtimer_cancel(session);
j1939_tp_schedule_txtimer(session, 0);
}
......@@ -1630,6 +1638,9 @@ j1939_session *j1939_xtp_rx_rts_session_new(struct j1939_priv *priv,
session->pkt.rx = 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));
return 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->last_cmd = dat[0];
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,
......
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