1 /* Copyright 2008-2016 Freescale Semiconductor, Inc.
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are met:
5 * * Redistributions of source code must retain the above copyright
6 * notice, this list of conditions and the following disclaimer.
7 * * Redistributions in binary form must reproduce the above copyright
8 * notice, this list of conditions and the following disclaimer in the
9 * documentation and/or other materials provided with the distribution.
10 * * Neither the name of Freescale Semiconductor nor the
11 * names of its contributors may be used to endorse or promote products
12 * derived from this software without specific prior written permission.
15 * ALTERNATIVELY, this software may be distributed under the terms of the
16 * GNU General Public License ("GPL") as published by the Free Software
17 * Foundation, either version 2 of that License or (at your option) any
20 * THIS SOFTWARE IS PROVIDED BY Freescale Semiconductor ``AS IS'' AND ANY
21 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
22 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 * DISCLAIMED. IN NO EVENT SHALL Freescale Semiconductor BE LIABLE FOR ANY
24 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
27 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
34 #include <linux/string.h>
35 #include <linux/of_platform.h>
36 #include <linux/net_tstamp.h>
37 #include <linux/fsl/ptp_qoriq.h>
42 static const char dpaa_stats_percpu
[][ETH_GSTRING_LEN
] = {
54 static char dpaa_stats_global
[][ETH_GSTRING_LEN
] = {
57 "rx frame physical error",
58 "rx frame size error",
61 /* demultiplexing errors */
71 /* congestion related stats */
72 "congestion time (ms)",
77 #define DPAA_STATS_PERCPU_LEN ARRAY_SIZE(dpaa_stats_percpu)
78 #define DPAA_STATS_GLOBAL_LEN ARRAY_SIZE(dpaa_stats_global)
80 static int dpaa_get_link_ksettings(struct net_device
*net_dev
,
81 struct ethtool_link_ksettings
*cmd
)
86 phy_ethtool_ksettings_get(net_dev
->phydev
, cmd
);
91 static int dpaa_set_link_ksettings(struct net_device
*net_dev
,
92 const struct ethtool_link_ksettings
*cmd
)
99 err
= phy_ethtool_ksettings_set(net_dev
->phydev
, cmd
);
101 netdev_err(net_dev
, "phy_ethtool_ksettings_set() = %d\n", err
);
106 static void dpaa_get_drvinfo(struct net_device
*net_dev
,
107 struct ethtool_drvinfo
*drvinfo
)
109 strlcpy(drvinfo
->driver
, KBUILD_MODNAME
,
110 sizeof(drvinfo
->driver
));
111 strlcpy(drvinfo
->bus_info
, dev_name(net_dev
->dev
.parent
->parent
),
112 sizeof(drvinfo
->bus_info
));
115 static u32
dpaa_get_msglevel(struct net_device
*net_dev
)
117 return ((struct dpaa_priv
*)netdev_priv(net_dev
))->msg_enable
;
120 static void dpaa_set_msglevel(struct net_device
*net_dev
,
123 ((struct dpaa_priv
*)netdev_priv(net_dev
))->msg_enable
= msg_enable
;
126 static int dpaa_nway_reset(struct net_device
*net_dev
)
130 if (!net_dev
->phydev
)
134 if (net_dev
->phydev
->autoneg
) {
135 err
= phy_start_aneg(net_dev
->phydev
);
137 netdev_err(net_dev
, "phy_start_aneg() = %d\n",
144 static void dpaa_get_pauseparam(struct net_device
*net_dev
,
145 struct ethtool_pauseparam
*epause
)
147 struct mac_device
*mac_dev
;
148 struct dpaa_priv
*priv
;
150 priv
= netdev_priv(net_dev
);
151 mac_dev
= priv
->mac_dev
;
153 if (!net_dev
->phydev
)
156 epause
->autoneg
= mac_dev
->autoneg_pause
;
157 epause
->rx_pause
= mac_dev
->rx_pause_active
;
158 epause
->tx_pause
= mac_dev
->tx_pause_active
;
161 static int dpaa_set_pauseparam(struct net_device
*net_dev
,
162 struct ethtool_pauseparam
*epause
)
164 struct mac_device
*mac_dev
;
165 struct phy_device
*phydev
;
166 bool rx_pause
, tx_pause
;
167 struct dpaa_priv
*priv
;
170 priv
= netdev_priv(net_dev
);
171 mac_dev
= priv
->mac_dev
;
173 phydev
= net_dev
->phydev
;
175 netdev_err(net_dev
, "phy device not initialized\n");
179 if (!phy_validate_pause(phydev
, epause
))
182 /* The MAC should know how to handle PAUSE frame autonegotiation before
183 * adjust_link is triggered by a forced renegotiation of sym/asym PAUSE
186 mac_dev
->autoneg_pause
= !!epause
->autoneg
;
187 mac_dev
->rx_pause_req
= !!epause
->rx_pause
;
188 mac_dev
->tx_pause_req
= !!epause
->tx_pause
;
190 /* Determine the sym/asym advertised PAUSE capabilities from the desired
191 * rx/tx pause settings.
194 phy_set_asym_pause(phydev
, epause
->rx_pause
, epause
->tx_pause
);
196 fman_get_pause_cfg(mac_dev
, &rx_pause
, &tx_pause
);
197 err
= fman_set_mac_active_pause(mac_dev
, rx_pause
, tx_pause
);
199 netdev_err(net_dev
, "set_mac_active_pause() = %d\n", err
);
204 static int dpaa_get_sset_count(struct net_device
*net_dev
, int type
)
206 unsigned int total_stats
, num_stats
;
208 num_stats
= num_online_cpus() + 1;
209 total_stats
= num_stats
* (DPAA_STATS_PERCPU_LEN
+ 1) +
210 DPAA_STATS_GLOBAL_LEN
;
220 static void copy_stats(struct dpaa_percpu_priv
*percpu_priv
, int num_cpus
,
221 int crr_cpu
, u64 bp_count
, u64
*data
)
223 int num_values
= num_cpus
+ 1;
226 /* update current CPU's stats and also add them to the total values */
227 data
[crr
* num_values
+ crr_cpu
] = percpu_priv
->in_interrupt
;
228 data
[crr
++ * num_values
+ num_cpus
] += percpu_priv
->in_interrupt
;
230 data
[crr
* num_values
+ crr_cpu
] = percpu_priv
->stats
.rx_packets
;
231 data
[crr
++ * num_values
+ num_cpus
] += percpu_priv
->stats
.rx_packets
;
233 data
[crr
* num_values
+ crr_cpu
] = percpu_priv
->stats
.tx_packets
;
234 data
[crr
++ * num_values
+ num_cpus
] += percpu_priv
->stats
.tx_packets
;
236 data
[crr
* num_values
+ crr_cpu
] = percpu_priv
->tx_confirm
;
237 data
[crr
++ * num_values
+ num_cpus
] += percpu_priv
->tx_confirm
;
239 data
[crr
* num_values
+ crr_cpu
] = percpu_priv
->tx_frag_skbuffs
;
240 data
[crr
++ * num_values
+ num_cpus
] += percpu_priv
->tx_frag_skbuffs
;
242 data
[crr
* num_values
+ crr_cpu
] = percpu_priv
->stats
.tx_errors
;
243 data
[crr
++ * num_values
+ num_cpus
] += percpu_priv
->stats
.tx_errors
;
245 data
[crr
* num_values
+ crr_cpu
] = percpu_priv
->stats
.rx_errors
;
246 data
[crr
++ * num_values
+ num_cpus
] += percpu_priv
->stats
.rx_errors
;
248 data
[crr
* num_values
+ crr_cpu
] = percpu_priv
->stats
.rx_dropped
;
249 data
[crr
++ * num_values
+ num_cpus
] += percpu_priv
->stats
.rx_dropped
;
251 data
[crr
* num_values
+ crr_cpu
] = percpu_priv
->stats
.tx_dropped
;
252 data
[crr
++ * num_values
+ num_cpus
] += percpu_priv
->stats
.tx_dropped
;
254 data
[crr
* num_values
+ crr_cpu
] = bp_count
;
255 data
[crr
++ * num_values
+ num_cpus
] += bp_count
;
258 static void dpaa_get_ethtool_stats(struct net_device
*net_dev
,
259 struct ethtool_stats
*stats
, u64
*data
)
261 struct dpaa_percpu_priv
*percpu_priv
;
262 struct dpaa_rx_errors rx_errors
;
263 unsigned int num_cpus
, offset
;
264 u64 bp_count
, cg_time
, cg_num
;
265 struct dpaa_ern_cnt ern_cnt
;
266 struct dpaa_bp
*dpaa_bp
;
267 struct dpaa_priv
*priv
;
271 total_stats
= dpaa_get_sset_count(net_dev
, ETH_SS_STATS
);
272 priv
= netdev_priv(net_dev
);
273 num_cpus
= num_online_cpus();
275 memset(&bp_count
, 0, sizeof(bp_count
));
276 memset(&rx_errors
, 0, sizeof(struct dpaa_rx_errors
));
277 memset(&ern_cnt
, 0, sizeof(struct dpaa_ern_cnt
));
278 memset(data
, 0, total_stats
* sizeof(u64
));
280 for_each_online_cpu(i
) {
281 percpu_priv
= per_cpu_ptr(priv
->percpu_priv
, i
);
282 dpaa_bp
= priv
->dpaa_bp
;
283 if (!dpaa_bp
->percpu_count
)
285 bp_count
= *(per_cpu_ptr(dpaa_bp
->percpu_count
, i
));
286 rx_errors
.dme
+= percpu_priv
->rx_errors
.dme
;
287 rx_errors
.fpe
+= percpu_priv
->rx_errors
.fpe
;
288 rx_errors
.fse
+= percpu_priv
->rx_errors
.fse
;
289 rx_errors
.phe
+= percpu_priv
->rx_errors
.phe
;
291 ern_cnt
.cg_tdrop
+= percpu_priv
->ern_cnt
.cg_tdrop
;
292 ern_cnt
.wred
+= percpu_priv
->ern_cnt
.wred
;
293 ern_cnt
.err_cond
+= percpu_priv
->ern_cnt
.err_cond
;
294 ern_cnt
.early_window
+= percpu_priv
->ern_cnt
.early_window
;
295 ern_cnt
.late_window
+= percpu_priv
->ern_cnt
.late_window
;
296 ern_cnt
.fq_tdrop
+= percpu_priv
->ern_cnt
.fq_tdrop
;
297 ern_cnt
.fq_retired
+= percpu_priv
->ern_cnt
.fq_retired
;
298 ern_cnt
.orp_zero
+= percpu_priv
->ern_cnt
.orp_zero
;
300 copy_stats(percpu_priv
, num_cpus
, i
, bp_count
, data
);
303 offset
= (num_cpus
+ 1) * (DPAA_STATS_PERCPU_LEN
+ 1);
304 memcpy(data
+ offset
, &rx_errors
, sizeof(struct dpaa_rx_errors
));
306 offset
+= sizeof(struct dpaa_rx_errors
) / sizeof(u64
);
307 memcpy(data
+ offset
, &ern_cnt
, sizeof(struct dpaa_ern_cnt
));
309 /* gather congestion related counters */
312 cg_time
= jiffies_to_msecs(priv
->cgr_data
.congested_jiffies
);
313 if (qman_query_cgr_congested(&priv
->cgr_data
.cgr
, &cg_status
) == 0) {
314 cg_num
= priv
->cgr_data
.cgr_congested_count
;
316 /* reset congestion stats (like QMan API does */
317 priv
->cgr_data
.congested_jiffies
= 0;
318 priv
->cgr_data
.cgr_congested_count
= 0;
321 offset
+= sizeof(struct dpaa_ern_cnt
) / sizeof(u64
);
322 data
[offset
++] = cg_time
;
323 data
[offset
++] = cg_num
;
324 data
[offset
++] = cg_status
;
327 static void dpaa_get_strings(struct net_device
*net_dev
, u32 stringset
,
330 unsigned int i
, j
, num_cpus
, size
;
331 char string_cpu
[ETH_GSTRING_LEN
];
334 memset(string_cpu
, 0, sizeof(string_cpu
));
336 num_cpus
= num_online_cpus();
337 size
= DPAA_STATS_GLOBAL_LEN
* ETH_GSTRING_LEN
;
339 for (i
= 0; i
< DPAA_STATS_PERCPU_LEN
; i
++) {
340 for (j
= 0; j
< num_cpus
; j
++) {
341 snprintf(string_cpu
, ETH_GSTRING_LEN
, "%s [CPU %d]",
342 dpaa_stats_percpu
[i
], j
);
343 memcpy(strings
, string_cpu
, ETH_GSTRING_LEN
);
344 strings
+= ETH_GSTRING_LEN
;
346 snprintf(string_cpu
, ETH_GSTRING_LEN
, "%s [TOTAL]",
347 dpaa_stats_percpu
[i
]);
348 memcpy(strings
, string_cpu
, ETH_GSTRING_LEN
);
349 strings
+= ETH_GSTRING_LEN
;
351 for (j
= 0; j
< num_cpus
; j
++) {
352 snprintf(string_cpu
, ETH_GSTRING_LEN
,
353 "bpool [CPU %d]", j
);
354 memcpy(strings
, string_cpu
, ETH_GSTRING_LEN
);
355 strings
+= ETH_GSTRING_LEN
;
357 snprintf(string_cpu
, ETH_GSTRING_LEN
, "bpool [TOTAL]");
358 memcpy(strings
, string_cpu
, ETH_GSTRING_LEN
);
359 strings
+= ETH_GSTRING_LEN
;
361 memcpy(strings
, dpaa_stats_global
, size
);
364 static int dpaa_get_hash_opts(struct net_device
*dev
,
365 struct ethtool_rxnfc
*cmd
)
367 struct dpaa_priv
*priv
= netdev_priv(dev
);
371 switch (cmd
->flow_type
) {
376 if (priv
->keygen_in_use
)
377 cmd
->data
|= RXH_L4_B_0_1
| RXH_L4_B_2_3
;
389 if (priv
->keygen_in_use
)
390 cmd
->data
|= RXH_IP_SRC
| RXH_IP_DST
;
400 static int dpaa_get_rxnfc(struct net_device
*dev
, struct ethtool_rxnfc
*cmd
,
403 int ret
= -EOPNOTSUPP
;
407 ret
= dpaa_get_hash_opts(dev
, cmd
);
416 static void dpaa_set_hash(struct net_device
*net_dev
, bool enable
)
418 struct mac_device
*mac_dev
;
419 struct fman_port
*rxport
;
420 struct dpaa_priv
*priv
;
422 priv
= netdev_priv(net_dev
);
423 mac_dev
= priv
->mac_dev
;
424 rxport
= mac_dev
->port
[0];
426 fman_port_use_kg_hash(rxport
, enable
);
427 priv
->keygen_in_use
= enable
;
430 static int dpaa_set_hash_opts(struct net_device
*dev
,
431 struct ethtool_rxnfc
*nfc
)
435 /* we support hashing on IPv4/v6 src/dest IP and L4 src/dest port */
437 ~(RXH_IP_SRC
| RXH_IP_DST
| RXH_L4_B_0_1
| RXH_L4_B_2_3
))
440 switch (nfc
->flow_type
) {
455 dpaa_set_hash(dev
, !!nfc
->data
);
465 static int dpaa_set_rxnfc(struct net_device
*dev
, struct ethtool_rxnfc
*cmd
)
467 int ret
= -EOPNOTSUPP
;
471 ret
= dpaa_set_hash_opts(dev
, cmd
);
480 static int dpaa_get_ts_info(struct net_device
*net_dev
,
481 struct ethtool_ts_info
*info
)
483 struct device
*dev
= net_dev
->dev
.parent
;
484 struct device_node
*mac_node
= dev
->of_node
;
485 struct device_node
*fman_node
= NULL
, *ptp_node
= NULL
;
486 struct platform_device
*ptp_dev
= NULL
;
487 struct ptp_qoriq
*ptp
= NULL
;
489 info
->phc_index
= -1;
491 fman_node
= of_get_parent(mac_node
);
493 ptp_node
= of_parse_phandle(fman_node
, "ptimer-handle", 0);
496 ptp_dev
= of_find_device_by_node(ptp_node
);
499 ptp
= platform_get_drvdata(ptp_dev
);
502 info
->phc_index
= ptp
->phc_index
;
504 info
->so_timestamping
= SOF_TIMESTAMPING_TX_HARDWARE
|
505 SOF_TIMESTAMPING_RX_HARDWARE
|
506 SOF_TIMESTAMPING_RAW_HARDWARE
;
507 info
->tx_types
= (1 << HWTSTAMP_TX_OFF
) |
508 (1 << HWTSTAMP_TX_ON
);
509 info
->rx_filters
= (1 << HWTSTAMP_FILTER_NONE
) |
510 (1 << HWTSTAMP_FILTER_ALL
);
515 static int dpaa_get_coalesce(struct net_device
*dev
,
516 struct ethtool_coalesce
*c
)
518 struct qman_portal
*portal
;
522 portal
= qman_get_affine_portal(smp_processor_id());
523 qman_portal_get_iperiod(portal
, &period
);
524 qman_dqrr_get_ithresh(portal
, &thresh
);
526 c
->rx_coalesce_usecs
= period
;
527 c
->rx_max_coalesced_frames
= thresh
;
532 static int dpaa_set_coalesce(struct net_device
*dev
,
533 struct ethtool_coalesce
*c
)
535 const cpumask_t
*cpus
= qman_affine_cpus();
536 bool needs_revert
[NR_CPUS
] = {false};
537 struct qman_portal
*portal
;
538 u32 period
, prev_period
;
539 u8 thresh
, prev_thresh
;
542 period
= c
->rx_coalesce_usecs
;
543 thresh
= c
->rx_max_coalesced_frames
;
545 /* save previous values */
546 portal
= qman_get_affine_portal(smp_processor_id());
547 qman_portal_get_iperiod(portal
, &prev_period
);
548 qman_dqrr_get_ithresh(portal
, &prev_thresh
);
551 for_each_cpu_and(cpu
, cpus
, cpu_online_mask
) {
552 portal
= qman_get_affine_portal(cpu
);
553 res
= qman_portal_set_iperiod(portal
, period
);
556 res
= qman_dqrr_set_ithresh(portal
, thresh
);
558 qman_portal_set_iperiod(portal
, prev_period
);
561 needs_revert
[cpu
] = true;
567 /* restore previous values */
568 for_each_cpu_and(cpu
, cpus
, cpu_online_mask
) {
569 if (!needs_revert
[cpu
])
571 portal
= qman_get_affine_portal(cpu
);
572 /* previous values will not fail, ignore return value */
573 qman_portal_set_iperiod(portal
, prev_period
);
574 qman_dqrr_set_ithresh(portal
, prev_thresh
);
580 const struct ethtool_ops dpaa_ethtool_ops
= {
581 .supported_coalesce_params
= ETHTOOL_COALESCE_RX_USECS
|
582 ETHTOOL_COALESCE_RX_MAX_FRAMES
,
583 .get_drvinfo
= dpaa_get_drvinfo
,
584 .get_msglevel
= dpaa_get_msglevel
,
585 .set_msglevel
= dpaa_set_msglevel
,
586 .nway_reset
= dpaa_nway_reset
,
587 .get_pauseparam
= dpaa_get_pauseparam
,
588 .set_pauseparam
= dpaa_set_pauseparam
,
589 .get_link
= ethtool_op_get_link
,
590 .get_sset_count
= dpaa_get_sset_count
,
591 .get_ethtool_stats
= dpaa_get_ethtool_stats
,
592 .get_strings
= dpaa_get_strings
,
593 .get_link_ksettings
= dpaa_get_link_ksettings
,
594 .set_link_ksettings
= dpaa_set_link_ksettings
,
595 .get_rxnfc
= dpaa_get_rxnfc
,
596 .set_rxnfc
= dpaa_set_rxnfc
,
597 .get_ts_info
= dpaa_get_ts_info
,
598 .get_coalesce
= dpaa_get_coalesce
,
599 .set_coalesce
= dpaa_set_coalesce
,