Commit | Line | Data |
---|---|---|
d86ba8db MKB |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // | |
3 | // mcp251xfd - Microchip MCP251xFD Family CAN controller driver | |
4 | // | |
5 | // Copyright (c) 2021, 2022 Pengutronix, | |
6 | // Marc Kleine-Budde <kernel@pengutronix.de> | |
7 | // | |
8 | ||
9 | #include <linux/ethtool.h> | |
10 | ||
11 | #include "mcp251xfd.h" | |
9263c2e9 | 12 | #include "mcp251xfd-ram.h" |
d86ba8db MKB |
13 | |
14 | static void | |
15 | mcp251xfd_ring_get_ringparam(struct net_device *ndev, | |
16 | struct ethtool_ringparam *ring, | |
17 | struct kernel_ethtool_ringparam *kernel_ring, | |
18 | struct netlink_ext_ack *extack) | |
19 | { | |
20 | const struct mcp251xfd_priv *priv = netdev_priv(ndev); | |
9263c2e9 MKB |
21 | const bool fd_mode = mcp251xfd_is_fd_mode(priv); |
22 | struct can_ram_layout layout; | |
d86ba8db | 23 | |
9263c2e9 MKB |
24 | can_ram_get_layout(&layout, &mcp251xfd_ram_config, NULL, NULL, fd_mode); |
25 | ring->rx_max_pending = layout.max_rx; | |
26 | ring->tx_max_pending = layout.max_tx; | |
d86ba8db MKB |
27 | |
28 | ring->rx_pending = priv->rx_obj_num; | |
29 | ring->tx_pending = priv->tx->obj_num; | |
30 | } | |
31 | ||
9263c2e9 MKB |
32 | static int |
33 | mcp251xfd_ring_set_ringparam(struct net_device *ndev, | |
34 | struct ethtool_ringparam *ring, | |
35 | struct kernel_ethtool_ringparam *kernel_ring, | |
36 | struct netlink_ext_ack *extack) | |
37 | { | |
38 | struct mcp251xfd_priv *priv = netdev_priv(ndev); | |
39 | const bool fd_mode = mcp251xfd_is_fd_mode(priv); | |
40 | struct can_ram_layout layout; | |
41 | ||
42 | can_ram_get_layout(&layout, &mcp251xfd_ram_config, ring, NULL, fd_mode); | |
43 | if ((layout.cur_rx != priv->rx_obj_num || | |
44 | layout.cur_tx != priv->tx->obj_num) && | |
45 | netif_running(ndev)) | |
46 | return -EBUSY; | |
47 | ||
48 | priv->rx_obj_num = layout.cur_rx; | |
846990e0 MKB |
49 | priv->rx_obj_num_coalesce_irq = layout.rx_coalesce; |
50 | priv->tx->obj_num = layout.cur_tx; | |
1613fff7 | 51 | priv->tx_obj_num_coalesce_irq = layout.tx_coalesce; |
846990e0 MKB |
52 | |
53 | return 0; | |
54 | } | |
55 | ||
56 | static int mcp251xfd_ring_get_coalesce(struct net_device *ndev, | |
57 | struct ethtool_coalesce *ec, | |
58 | struct kernel_ethtool_coalesce *kec, | |
59 | struct netlink_ext_ack *ext_ack) | |
60 | { | |
61 | struct mcp251xfd_priv *priv = netdev_priv(ndev); | |
656fc12d | 62 | u32 rx_max_frames, tx_max_frames; |
846990e0 MKB |
63 | |
64 | /* The ethtool doc says: | |
65 | * To disable coalescing, set usecs = 0 and max_frames = 1. | |
66 | */ | |
67 | if (priv->rx_obj_num_coalesce_irq == 0) | |
68 | rx_max_frames = 1; | |
69 | else | |
70 | rx_max_frames = priv->rx_obj_num_coalesce_irq; | |
71 | ||
72 | ec->rx_max_coalesced_frames_irq = rx_max_frames; | |
73 | ec->rx_coalesce_usecs_irq = priv->rx_coalesce_usecs_irq; | |
74 | ||
656fc12d MKB |
75 | if (priv->tx_obj_num_coalesce_irq == 0) |
76 | tx_max_frames = 1; | |
77 | else | |
78 | tx_max_frames = priv->tx_obj_num_coalesce_irq; | |
79 | ||
80 | ec->tx_max_coalesced_frames_irq = tx_max_frames; | |
81 | ec->tx_coalesce_usecs_irq = priv->tx_coalesce_usecs_irq; | |
82 | ||
846990e0 MKB |
83 | return 0; |
84 | } | |
85 | ||
86 | static int mcp251xfd_ring_set_coalesce(struct net_device *ndev, | |
87 | struct ethtool_coalesce *ec, | |
88 | struct kernel_ethtool_coalesce *kec, | |
89 | struct netlink_ext_ack *ext_ack) | |
90 | { | |
91 | struct mcp251xfd_priv *priv = netdev_priv(ndev); | |
92 | const bool fd_mode = mcp251xfd_is_fd_mode(priv); | |
93 | const struct ethtool_ringparam ring = { | |
94 | .rx_pending = priv->rx_obj_num, | |
95 | .tx_pending = priv->tx->obj_num, | |
96 | }; | |
97 | struct can_ram_layout layout; | |
98 | ||
99 | can_ram_get_layout(&layout, &mcp251xfd_ram_config, &ring, ec, fd_mode); | |
100 | ||
101 | if ((layout.rx_coalesce != priv->rx_obj_num_coalesce_irq || | |
656fc12d MKB |
102 | ec->rx_coalesce_usecs_irq != priv->rx_coalesce_usecs_irq || |
103 | layout.tx_coalesce != priv->tx_obj_num_coalesce_irq || | |
104 | ec->tx_coalesce_usecs_irq != priv->tx_coalesce_usecs_irq) && | |
846990e0 MKB |
105 | netif_running(ndev)) |
106 | return -EBUSY; | |
107 | ||
108 | priv->rx_obj_num = layout.cur_rx; | |
109 | priv->rx_obj_num_coalesce_irq = layout.rx_coalesce; | |
110 | priv->rx_coalesce_usecs_irq = ec->rx_coalesce_usecs_irq; | |
656fc12d | 111 | |
9263c2e9 | 112 | priv->tx->obj_num = layout.cur_tx; |
656fc12d MKB |
113 | priv->tx_obj_num_coalesce_irq = layout.tx_coalesce; |
114 | priv->tx_coalesce_usecs_irq = ec->tx_coalesce_usecs_irq; | |
9263c2e9 MKB |
115 | |
116 | return 0; | |
117 | } | |
118 | ||
d86ba8db | 119 | static const struct ethtool_ops mcp251xfd_ethtool_ops = { |
846990e0 | 120 | .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS_IRQ | |
656fc12d MKB |
121 | ETHTOOL_COALESCE_RX_MAX_FRAMES_IRQ | |
122 | ETHTOOL_COALESCE_TX_USECS_IRQ | | |
123 | ETHTOOL_COALESCE_TX_MAX_FRAMES_IRQ, | |
d86ba8db | 124 | .get_ringparam = mcp251xfd_ring_get_ringparam, |
9263c2e9 | 125 | .set_ringparam = mcp251xfd_ring_set_ringparam, |
846990e0 MKB |
126 | .get_coalesce = mcp251xfd_ring_get_coalesce, |
127 | .set_coalesce = mcp251xfd_ring_set_coalesce, | |
b1f6b93e | 128 | .get_ts_info = can_ethtool_op_get_ts_info_hwts, |
d86ba8db MKB |
129 | }; |
130 | ||
131 | void mcp251xfd_ethtool_init(struct mcp251xfd_priv *priv) | |
132 | { | |
9263c2e9 MKB |
133 | struct can_ram_layout layout; |
134 | ||
d86ba8db | 135 | priv->ndev->ethtool_ops = &mcp251xfd_ethtool_ops; |
9263c2e9 MKB |
136 | |
137 | can_ram_get_layout(&layout, &mcp251xfd_ram_config, NULL, NULL, false); | |
138 | priv->rx_obj_num = layout.default_rx; | |
139 | priv->tx->obj_num = layout.default_tx; | |
60a848c5 MKB |
140 | |
141 | priv->rx_obj_num_coalesce_irq = 0; | |
656fc12d | 142 | priv->tx_obj_num_coalesce_irq = 0; |
60a848c5 | 143 | priv->rx_coalesce_usecs_irq = 0; |
656fc12d | 144 | priv->tx_coalesce_usecs_irq = 0; |
d86ba8db | 145 | } |