mirror of
https://github.com/torvalds/linux.git
synced 2025-04-12 16:47:42 +00:00
linux-can-next-for-6.14-20250110
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEUEC6huC2BN0pvD5fKDiiPnotvG8FAmeA/ocTHG1rbEBwZW5n dXRyb25peC5kZQAKCRAoOKI+ei28b7FlB/9c3ThnLVI/eezSZGE2UpvjN3eZWemk UkTxypJ9NpJkd1UovpOGVTNjAmlN+6+yjATJm8GBpSg99cN5Y8gcu7lWnsnidopm mkUNE+ZPPmkxe/ay1d6BfqJKzZTqkdJ6w1QlIXFfDgbRr4YaX9bn3egdtoNhq4fR 0qRt6++7V3hhhlr3x0hrhB+3nrTkL8eVBVWNEKFPCnCn9E3p7izXwZAG/y/IC4sP swTk1BbSZg9ajds/1DE2AVeUvqz63FnzjY7YChU5WdNY5bq/cFHGoCWn8aZEX/kC YFrQC3lonlNa/A5IFfb32HaFT0qFFbOKBHXru/wFuuwJCKVLUKsmLsd/ =c3SH -----END PGP SIGNATURE----- Merge tag 'linux-can-next-for-6.14-20250110' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next Marc Kleine-Budde says: ==================== pull-request: can-next 2025-01-10 Pierre-Henry Moussay adds PIC64GX compatibility to the DT bindings for Microchip's mpfs-can IP core. The next 3 patches are by Sean Nyekjaer and target the tcan4x5x driver. First the DT bindings is converted to DT schema, then nWKRQ voltage selection is added to the driver. Dario Binacchi's patch for the sun4i_can makes the driver more consistent by adding a likely() to the driver. Another patch by Sean Nyekjaer for the tcan4x5x driver gets rid of a false error message. Charan Pedumuru converts the atmel-can DT bindings to DT schema. The next 2 patches are by Oliver Hartkopp. The first one maps Oliver's former mail addresses to a dedicated CAN mail address. The second one assigns net/sched/em_canid.c additionally to the CAN maintainers. Ariel Otilibili's patch removes dead code from the CAN dev helper. The next 3 patches are by Sean Nyekjaer and add HW standby support to the tcan4x5x driver. A patch by Dario Binacchi fixes the DT bindings for the st,stm32-bxcan driver. The last 4 patches are by Jimmy Assarsson and target the kvaser_usb and the kvaser_pciefd driver: error statistics are improved and CAN_CTRLMODE_BERR_REPORTING is added. * tag 'linux-can-next-for-6.14-20250110' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next: can: kvaser_pciefd: Add support for CAN_CTRLMODE_BERR_REPORTING can: kvaser_pciefd: Update stats and state even if alloc_can_err_skb() fails can: kvaser_usb: Add support for CAN_CTRLMODE_BERR_REPORTING can: kvaser_usb: Update stats and state even if alloc_can_err_skb() fails dt-bindings: can: st,stm32-bxcan: fix st,gcan property type can: m_can: call deinit/init callback when going into suspend/resume can: tcan4x5x: add deinit callback to set standby mode can: m_can: add deinit callback can: dev: can_get_state_str(): Remove dead code MAINTAINERS: assign em_canid.c additionally to CAN maintainers mailmap: add an entry for Oliver Hartkopp dt-bindings: net: can: atmel: Convert to json schema can: tcan4x5x: get rid of false clock errors can: sun4i_can: continue to use likely() to check skb can: tcan4x5x: add option for selecting nWKRQ voltage dt-bindings: can: tcan4x5x: Document the ti,nwkrq-voltage-vio option dt-bindings: can: convert tcan4x5x.txt to DT schema dt-bindings: can: mpfs: add PIC64GX CAN compatibility ==================== Link: https://patch.msgid.link/20250110112712.3214173-1-mkl@pengutronix.de Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
commit
7dc8f809b8
2
.mailmap
2
.mailmap
@ -529,6 +529,8 @@ Oleksij Rempel <linux@rempel-privat.de> <external.Oleksij.Rempel@de.bosch.com>
|
||||
Oleksij Rempel <linux@rempel-privat.de> <fixed-term.Oleksij.Rempel@de.bosch.com>
|
||||
Oleksij Rempel <o.rempel@pengutronix.de>
|
||||
Oleksij Rempel <o.rempel@pengutronix.de> <ore@pengutronix.de>
|
||||
Oliver Hartkopp <socketcan@hartkopp.net> <oliver.hartkopp@volkswagen.de>
|
||||
Oliver Hartkopp <socketcan@hartkopp.net> <oliver@hartkopp.net>
|
||||
Oliver Upton <oliver.upton@linux.dev> <oupton@google.com>
|
||||
Ondřej Jirman <megi@xff.cz> <megous@megous.com>
|
||||
Oza Pawandeep <quic_poza@quicinc.com> <poza@codeaurora.org>
|
||||
|
@ -0,0 +1,58 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/can/atmel,at91sam9263-can.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Microchip AT91 CAN Controller
|
||||
|
||||
maintainers:
|
||||
- Nicolas Ferre <nicolas.ferre@microchip.com>
|
||||
|
||||
allOf:
|
||||
- $ref: can-controller.yaml#
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- enum:
|
||||
- atmel,at91sam9263-can
|
||||
- atmel,at91sam9x5-can
|
||||
- items:
|
||||
- enum:
|
||||
- microchip,sam9x60-can
|
||||
- const: atmel,at91sam9x5-can
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: can_clk
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
#include <dt-bindings/clock/at91.h>
|
||||
can@f000c000 {
|
||||
compatible = "atmel,at91sam9263-can";
|
||||
reg = <0xf000c000 0x300>;
|
||||
interrupts = <30 IRQ_TYPE_LEVEL_HIGH 3>;
|
||||
clocks = <&pmc PMC_TYPE_PERIPHERAL 12>;
|
||||
clock-names = "can_clk";
|
||||
};
|
@ -1,15 +0,0 @@
|
||||
* AT91 CAN *
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "atmel,at91sam9263-can", "atmel,at91sam9x5-can" or
|
||||
"microchip,sam9x60-can"
|
||||
- reg: Should contain CAN controller registers location and length
|
||||
- interrupts: Should contain IRQ line for the CAN controller
|
||||
|
||||
Example:
|
||||
|
||||
can0: can@f000c000 {
|
||||
compatible = "atmel,at91sam9x5-can";
|
||||
reg = <0xf000c000 0x300>;
|
||||
interrupts = <40 4 5>
|
||||
};
|
@ -15,7 +15,11 @@ allOf:
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
const: microchip,mpfs-can
|
||||
oneOf:
|
||||
- items:
|
||||
- const: microchip,pic64gx-can
|
||||
- const: microchip,mpfs-can
|
||||
- const: microchip,mpfs-can
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
@ -63,7 +63,7 @@ properties:
|
||||
maxItems: 1
|
||||
|
||||
st,gcan:
|
||||
$ref: /schemas/types.yaml#/definitions/phandle-array
|
||||
$ref: /schemas/types.yaml#/definitions/phandle
|
||||
description:
|
||||
The phandle to the gcan node which allows to access the 512-bytes
|
||||
SRAM memory shared by the two bxCAN cells (CAN1 primary and CAN2
|
||||
|
@ -1,48 +0,0 @@
|
||||
Texas Instruments TCAN4x5x CAN Controller
|
||||
================================================
|
||||
|
||||
This file provides device node information for the TCAN4x5x interface contains.
|
||||
|
||||
Required properties:
|
||||
- compatible:
|
||||
"ti,tcan4552", "ti,tcan4x5x"
|
||||
"ti,tcan4553", "ti,tcan4x5x" or
|
||||
"ti,tcan4x5x"
|
||||
- reg: 0
|
||||
- #address-cells: 1
|
||||
- #size-cells: 0
|
||||
- spi-max-frequency: Maximum frequency of the SPI bus the chip can
|
||||
operate at should be less than or equal to 18 MHz.
|
||||
- interrupt-parent: the phandle to the interrupt controller which provides
|
||||
the interrupt.
|
||||
- interrupts: interrupt specification for data-ready.
|
||||
|
||||
See Documentation/devicetree/bindings/net/can/bosch,m_can.yaml for additional
|
||||
required property details.
|
||||
|
||||
Optional properties:
|
||||
- reset-gpios: Hardwired output GPIO. If not defined then software
|
||||
reset.
|
||||
- device-state-gpios: Input GPIO that indicates if the device is in
|
||||
a sleep state or if the device is active. Not
|
||||
available with tcan4552/4553.
|
||||
- device-wake-gpios: Wake up GPIO to wake up the TCAN device. Not
|
||||
available with tcan4552/4553.
|
||||
- wakeup-source: Leave the chip running when suspended, and configure
|
||||
the RX interrupt to wake up the device.
|
||||
|
||||
Example:
|
||||
tcan4x5x: tcan4x5x@0 {
|
||||
compatible = "ti,tcan4x5x";
|
||||
reg = <0>;
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
spi-max-frequency = <10000000>;
|
||||
bosch,mram-cfg = <0x0 0 0 16 0 0 1 1>;
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <14 IRQ_TYPE_LEVEL_LOW>;
|
||||
device-state-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>;
|
||||
device-wake-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>;
|
||||
reset-gpios = <&gpio1 27 GPIO_ACTIVE_HIGH>;
|
||||
wakeup-source;
|
||||
};
|
199
Documentation/devicetree/bindings/net/can/ti,tcan4x5x.yaml
Normal file
199
Documentation/devicetree/bindings/net/can/ti,tcan4x5x.yaml
Normal file
@ -0,0 +1,199 @@
|
||||
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
|
||||
%YAML 1.2
|
||||
---
|
||||
$id: http://devicetree.org/schemas/net/can/ti,tcan4x5x.yaml#
|
||||
$schema: http://devicetree.org/meta-schemas/core.yaml#
|
||||
|
||||
title: Texas Instruments TCAN4x5x CAN Controller
|
||||
|
||||
maintainers:
|
||||
- Marc Kleine-Budde <mkl@pengutronix.de>
|
||||
|
||||
properties:
|
||||
compatible:
|
||||
oneOf:
|
||||
- items:
|
||||
- enum:
|
||||
- ti,tcan4552
|
||||
- ti,tcan4553
|
||||
- const: ti,tcan4x5x
|
||||
- const: ti,tcan4x5x
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
interrupts:
|
||||
maxItems: 1
|
||||
description: The GPIO parent interrupt.
|
||||
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
clock-names:
|
||||
items:
|
||||
- const: cclk
|
||||
|
||||
reset-gpios:
|
||||
description: Hardwired output GPIO. If not defined then software reset.
|
||||
maxItems: 1
|
||||
|
||||
device-state-gpios:
|
||||
description:
|
||||
Input GPIO that indicates if the device is in a sleep state or if the
|
||||
device is active. Not available with tcan4552/4553.
|
||||
maxItems: 1
|
||||
|
||||
device-wake-gpios:
|
||||
description:
|
||||
Wake up GPIO to wake up the TCAN device.
|
||||
Not available with tcan4552/4553.
|
||||
maxItems: 1
|
||||
|
||||
bosch,mram-cfg:
|
||||
description: |
|
||||
Message RAM configuration data.
|
||||
Multiple M_CAN instances can share the same Message RAM
|
||||
and each element(e.g Rx FIFO or Tx Buffer and etc) number
|
||||
in Message RAM is also configurable, so this property is
|
||||
telling driver how the shared or private Message RAM are
|
||||
used by this M_CAN controller.
|
||||
|
||||
The format should be as follows:
|
||||
<offset sidf_elems xidf_elems rxf0_elems rxf1_elems rxb_elems txe_elems txb_elems>
|
||||
The 'offset' is an address offset of the Message RAM where
|
||||
the following elements start from. This is usually set to
|
||||
0x0 if you're using a private Message RAM. The remain cells
|
||||
are used to specify how many elements are used for each FIFO/Buffer.
|
||||
|
||||
M_CAN includes the following elements according to user manual:
|
||||
11-bit Filter 0-128 elements / 0-128 words
|
||||
29-bit Filter 0-64 elements / 0-128 words
|
||||
Rx FIFO 0 0-64 elements / 0-1152 words
|
||||
Rx FIFO 1 0-64 elements / 0-1152 words
|
||||
Rx Buffers 0-64 elements / 0-1152 words
|
||||
Tx Event FIFO 0-32 elements / 0-64 words
|
||||
Tx Buffers 0-32 elements / 0-576 words
|
||||
|
||||
Please refer to 2.4.1 Message RAM Configuration in Bosch
|
||||
M_CAN user manual for details.
|
||||
$ref: /schemas/types.yaml#/definitions/int32-array
|
||||
items:
|
||||
- description: The 'offset' is an address offset of the Message RAM where
|
||||
the following elements start from. This is usually set to 0x0 if
|
||||
you're using a private Message RAM.
|
||||
default: 0
|
||||
- description: 11-bit Filter 0-128 elements / 0-128 words
|
||||
minimum: 0
|
||||
maximum: 128
|
||||
- description: 29-bit Filter 0-64 elements / 0-128 words
|
||||
minimum: 0
|
||||
maximum: 64
|
||||
- description: Rx FIFO 0 0-64 elements / 0-1152 words
|
||||
minimum: 0
|
||||
maximum: 64
|
||||
- description: Rx FIFO 1 0-64 elements / 0-1152 words
|
||||
minimum: 0
|
||||
maximum: 64
|
||||
- description: Rx Buffers 0-64 elements / 0-1152 words
|
||||
minimum: 0
|
||||
maximum: 64
|
||||
- description: Tx Event FIFO 0-32 elements / 0-64 words
|
||||
minimum: 0
|
||||
maximum: 32
|
||||
- description: Tx Buffers 0-32 elements / 0-576 words
|
||||
minimum: 0
|
||||
maximum: 32
|
||||
minItems: 1
|
||||
|
||||
spi-max-frequency:
|
||||
description:
|
||||
Must be half or less of "clocks" frequency.
|
||||
maximum: 18000000
|
||||
|
||||
ti,nwkrq-voltage-vio:
|
||||
type: boolean
|
||||
description:
|
||||
nWKRQ Pin GPO buffer voltage configuration.
|
||||
Set nWKRQ to use VIO voltage rail.
|
||||
When not set nWKRQ will use internal voltage rail.
|
||||
|
||||
wakeup-source:
|
||||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
Enable CAN remote wakeup.
|
||||
|
||||
allOf:
|
||||
- $ref: can-controller.yaml#
|
||||
- $ref: /schemas/spi/spi-peripheral-props.yaml#
|
||||
- if:
|
||||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
enum:
|
||||
- ti,tcan4552
|
||||
- ti,tcan4553
|
||||
then:
|
||||
properties:
|
||||
device-state-gpios: false
|
||||
device-wake-gpios: false
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- reg
|
||||
- interrupts
|
||||
- clocks
|
||||
- clock-names
|
||||
- bosch,mram-cfg
|
||||
|
||||
unevaluatedProperties: false
|
||||
|
||||
examples:
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
can@0 {
|
||||
compatible = "ti,tcan4x5x";
|
||||
reg = <0>;
|
||||
clocks = <&can0_osc>;
|
||||
clock-names = "cclk";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&can0_pins>;
|
||||
spi-max-frequency = <10000000>;
|
||||
bosch,mram-cfg = <0x0 0 0 16 0 0 1 1>;
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <14 IRQ_TYPE_LEVEL_LOW>;
|
||||
device-state-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>;
|
||||
device-wake-gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>;
|
||||
reset-gpios = <&gpio1 27 GPIO_ACTIVE_HIGH>;
|
||||
ti,nwkrq-voltage-vio;
|
||||
wakeup-source;
|
||||
};
|
||||
};
|
||||
- |
|
||||
#include <dt-bindings/gpio/gpio.h>
|
||||
#include <dt-bindings/interrupt-controller/irq.h>
|
||||
|
||||
spi {
|
||||
#address-cells = <1>;
|
||||
#size-cells = <0>;
|
||||
|
||||
can@0 {
|
||||
compatible = "ti,tcan4552", "ti,tcan4x5x";
|
||||
reg = <0>;
|
||||
clocks = <&can0_osc>;
|
||||
clock-names = "cclk";
|
||||
pinctrl-names = "default";
|
||||
pinctrl-0 = <&can0_pins>;
|
||||
spi-max-frequency = <10000000>;
|
||||
bosch,mram-cfg = <0x0 0 0 16 0 0 1 1>;
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <14 IRQ_TYPE_LEVEL_LOW>;
|
||||
reset-gpios = <&gpio1 27 GPIO_ACTIVE_HIGH>;
|
||||
wakeup-source;
|
||||
};
|
||||
};
|
@ -5115,6 +5115,7 @@ F: include/uapi/linux/can/gw.h
|
||||
F: include/uapi/linux/can/isotp.h
|
||||
F: include/uapi/linux/can/raw.h
|
||||
F: net/can/
|
||||
F: net/sched/em_canid.c
|
||||
|
||||
CAN-J1939 NETWORK LAYER
|
||||
M: Robin van der Gracht <robin@protonic.nl>
|
||||
|
@ -85,8 +85,6 @@ const char *can_get_state_str(const enum can_state state)
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
|
||||
return "<unknown>";
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(can_get_state_str);
|
||||
|
||||
|
@ -999,7 +999,8 @@ static int kvaser_pciefd_setup_can_ctrls(struct kvaser_pciefd *pcie)
|
||||
can->can.ctrlmode_supported = CAN_CTRLMODE_LISTENONLY |
|
||||
CAN_CTRLMODE_FD |
|
||||
CAN_CTRLMODE_FD_NON_ISO |
|
||||
CAN_CTRLMODE_CC_LEN8_DLC;
|
||||
CAN_CTRLMODE_CC_LEN8_DLC |
|
||||
CAN_CTRLMODE_BERR_REPORTING;
|
||||
|
||||
status = ioread32(can->reg_base + KVASER_PCIEFD_KCAN_STAT_REG);
|
||||
if (!(status & KVASER_PCIEFD_KCAN_STAT_FD)) {
|
||||
@ -1234,11 +1235,15 @@ static int kvaser_pciefd_handle_data_packet(struct kvaser_pciefd *pcie,
|
||||
}
|
||||
|
||||
static void kvaser_pciefd_change_state(struct kvaser_pciefd_can *can,
|
||||
const struct can_berr_counter *bec,
|
||||
struct can_frame *cf,
|
||||
enum can_state new_state,
|
||||
enum can_state tx_state,
|
||||
enum can_state rx_state)
|
||||
{
|
||||
enum can_state old_state;
|
||||
|
||||
old_state = can->can.state;
|
||||
can_change_state(can->can.dev, cf, tx_state, rx_state);
|
||||
|
||||
if (new_state == CAN_STATE_BUS_OFF) {
|
||||
@ -1254,6 +1259,18 @@ static void kvaser_pciefd_change_state(struct kvaser_pciefd_can *can,
|
||||
can_bus_off(ndev);
|
||||
}
|
||||
}
|
||||
if (old_state == CAN_STATE_BUS_OFF &&
|
||||
new_state == CAN_STATE_ERROR_ACTIVE &&
|
||||
can->can.restart_ms) {
|
||||
can->can.can_stats.restarts++;
|
||||
if (cf)
|
||||
cf->can_id |= CAN_ERR_RESTARTED;
|
||||
}
|
||||
if (cf && new_state != CAN_STATE_BUS_OFF) {
|
||||
cf->can_id |= CAN_ERR_CNT;
|
||||
cf->data[6] = bec->txerr;
|
||||
cf->data[7] = bec->rxerr;
|
||||
}
|
||||
}
|
||||
|
||||
static void kvaser_pciefd_packet_to_state(struct kvaser_pciefd_rx_packet *p,
|
||||
@ -1288,7 +1305,7 @@ static int kvaser_pciefd_rx_error_frame(struct kvaser_pciefd_can *can,
|
||||
struct can_berr_counter bec;
|
||||
enum can_state old_state, new_state, tx_state, rx_state;
|
||||
struct net_device *ndev = can->can.dev;
|
||||
struct sk_buff *skb;
|
||||
struct sk_buff *skb = NULL;
|
||||
struct can_frame *cf = NULL;
|
||||
|
||||
old_state = can->can.state;
|
||||
@ -1297,16 +1314,10 @@ static int kvaser_pciefd_rx_error_frame(struct kvaser_pciefd_can *can,
|
||||
bec.rxerr = FIELD_GET(KVASER_PCIEFD_SPACK_RXERR_MASK, p->header[0]);
|
||||
|
||||
kvaser_pciefd_packet_to_state(p, &bec, &new_state, &tx_state, &rx_state);
|
||||
if (can->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
|
||||
skb = alloc_can_err_skb(ndev, &cf);
|
||||
if (new_state != old_state) {
|
||||
kvaser_pciefd_change_state(can, cf, new_state, tx_state, rx_state);
|
||||
if (old_state == CAN_STATE_BUS_OFF &&
|
||||
new_state == CAN_STATE_ERROR_ACTIVE &&
|
||||
can->can.restart_ms) {
|
||||
can->can.can_stats.restarts++;
|
||||
if (skb)
|
||||
cf->can_id |= CAN_ERR_RESTARTED;
|
||||
}
|
||||
kvaser_pciefd_change_state(can, &bec, cf, new_state, tx_state, rx_state);
|
||||
}
|
||||
|
||||
can->err_rep_cnt++;
|
||||
@ -1319,17 +1330,18 @@ static int kvaser_pciefd_rx_error_frame(struct kvaser_pciefd_can *can,
|
||||
can->bec.txerr = bec.txerr;
|
||||
can->bec.rxerr = bec.rxerr;
|
||||
|
||||
if (can->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) {
|
||||
if (!skb) {
|
||||
netdev_warn(ndev, "No memory left for err_skb\n");
|
||||
ndev->stats.rx_dropped++;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
kvaser_pciefd_set_skb_timestamp(can->kv_pcie, skb, p->timestamp);
|
||||
cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_CNT;
|
||||
cf->data[6] = bec.txerr;
|
||||
cf->data[7] = bec.rxerr;
|
||||
|
||||
netif_rx(skb);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1359,6 +1371,7 @@ static int kvaser_pciefd_handle_status_resp(struct kvaser_pciefd_can *can,
|
||||
{
|
||||
struct can_berr_counter bec;
|
||||
enum can_state old_state, new_state, tx_state, rx_state;
|
||||
int ret = 0;
|
||||
|
||||
old_state = can->can.state;
|
||||
|
||||
@ -1372,25 +1385,15 @@ static int kvaser_pciefd_handle_status_resp(struct kvaser_pciefd_can *can,
|
||||
struct can_frame *cf;
|
||||
|
||||
skb = alloc_can_err_skb(ndev, &cf);
|
||||
if (!skb) {
|
||||
ndev->stats.rx_dropped++;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
kvaser_pciefd_change_state(can, cf, new_state, tx_state, rx_state);
|
||||
if (old_state == CAN_STATE_BUS_OFF &&
|
||||
new_state == CAN_STATE_ERROR_ACTIVE &&
|
||||
can->can.restart_ms) {
|
||||
can->can.can_stats.restarts++;
|
||||
cf->can_id |= CAN_ERR_RESTARTED;
|
||||
}
|
||||
|
||||
kvaser_pciefd_change_state(can, &bec, cf, new_state, tx_state, rx_state);
|
||||
if (skb) {
|
||||
kvaser_pciefd_set_skb_timestamp(can->kv_pcie, skb, p->timestamp);
|
||||
|
||||
cf->data[6] = bec.txerr;
|
||||
cf->data[7] = bec.rxerr;
|
||||
|
||||
netif_rx(skb);
|
||||
} else {
|
||||
ndev->stats.rx_dropped++;
|
||||
netdev_warn(ndev, "No memory left for err_skb\n");
|
||||
ret = -ENOMEM;
|
||||
}
|
||||
}
|
||||
can->bec.txerr = bec.txerr;
|
||||
can->bec.rxerr = bec.rxerr;
|
||||
@ -1398,7 +1401,7 @@ static int kvaser_pciefd_handle_status_resp(struct kvaser_pciefd_can *can,
|
||||
if (bec.txerr || bec.rxerr)
|
||||
mod_timer(&can->bec_poll_timer, KVASER_PCIEFD_BEC_POLL_FREQ);
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int kvaser_pciefd_handle_status_packet(struct kvaser_pciefd *pcie,
|
||||
|
@ -1785,6 +1785,13 @@ static void m_can_stop(struct net_device *dev)
|
||||
|
||||
/* set the state as STOPPED */
|
||||
cdev->can.state = CAN_STATE_STOPPED;
|
||||
|
||||
if (cdev->ops->deinit) {
|
||||
ret = cdev->ops->deinit(cdev);
|
||||
if (ret)
|
||||
netdev_err(dev, "failed to deinitialize: %pe\n",
|
||||
ERR_PTR(ret));
|
||||
}
|
||||
}
|
||||
|
||||
static int m_can_close(struct net_device *dev)
|
||||
@ -2466,6 +2473,7 @@ int m_can_class_suspend(struct device *dev)
|
||||
{
|
||||
struct m_can_classdev *cdev = dev_get_drvdata(dev);
|
||||
struct net_device *ndev = cdev->net;
|
||||
int ret = 0;
|
||||
|
||||
if (netif_running(ndev)) {
|
||||
netif_stop_queue(ndev);
|
||||
@ -2478,6 +2486,9 @@ int m_can_class_suspend(struct device *dev)
|
||||
if (cdev->pm_wake_source) {
|
||||
hrtimer_cancel(&cdev->hrtimer);
|
||||
m_can_write(cdev, M_CAN_IE, IR_RF0N);
|
||||
|
||||
if (cdev->ops->deinit)
|
||||
ret = cdev->ops->deinit(cdev);
|
||||
} else {
|
||||
m_can_stop(ndev);
|
||||
}
|
||||
@ -2489,7 +2500,7 @@ int m_can_class_suspend(struct device *dev)
|
||||
|
||||
cdev->can.state = CAN_STATE_SLEEPING;
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(m_can_class_suspend);
|
||||
|
||||
@ -2497,14 +2508,13 @@ int m_can_class_resume(struct device *dev)
|
||||
{
|
||||
struct m_can_classdev *cdev = dev_get_drvdata(dev);
|
||||
struct net_device *ndev = cdev->net;
|
||||
int ret = 0;
|
||||
|
||||
pinctrl_pm_select_default_state(dev);
|
||||
|
||||
cdev->can.state = CAN_STATE_ERROR_ACTIVE;
|
||||
|
||||
if (netif_running(ndev)) {
|
||||
int ret;
|
||||
|
||||
ret = m_can_clk_start(cdev);
|
||||
if (ret)
|
||||
return ret;
|
||||
@ -2517,6 +2527,10 @@ int m_can_class_resume(struct device *dev)
|
||||
* again.
|
||||
*/
|
||||
cdev->active_interrupts |= IR_RF0N | IR_TEFN;
|
||||
|
||||
if (cdev->ops->init)
|
||||
ret = cdev->ops->init(cdev);
|
||||
|
||||
m_can_write(cdev, M_CAN_IE, cdev->active_interrupts);
|
||||
} else {
|
||||
ret = m_can_start(ndev);
|
||||
@ -2530,7 +2544,7 @@ int m_can_class_resume(struct device *dev)
|
||||
netif_start_queue(ndev);
|
||||
}
|
||||
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(m_can_class_resume);
|
||||
|
||||
|
@ -68,6 +68,7 @@ struct m_can_ops {
|
||||
int (*write_fifo)(struct m_can_classdev *cdev, int addr_offset,
|
||||
const void *val, size_t val_count);
|
||||
int (*init)(struct m_can_classdev *cdev);
|
||||
int (*deinit)(struct m_can_classdev *cdev);
|
||||
};
|
||||
|
||||
struct m_can_tx_op {
|
||||
|
@ -92,6 +92,8 @@
|
||||
#define TCAN4X5X_MODE_STANDBY BIT(6)
|
||||
#define TCAN4X5X_MODE_NORMAL BIT(7)
|
||||
|
||||
#define TCAN4X5X_NWKRQ_VOLTAGE_VIO BIT(19)
|
||||
|
||||
#define TCAN4X5X_DISABLE_WAKE_MSK (BIT(31) | BIT(30))
|
||||
#define TCAN4X5X_DISABLE_INH_MSK BIT(9)
|
||||
|
||||
@ -267,9 +269,24 @@ static int tcan4x5x_init(struct m_can_classdev *cdev)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (tcan4x5x->nwkrq_voltage_vio) {
|
||||
ret = regmap_set_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG,
|
||||
TCAN4X5X_NWKRQ_VOLTAGE_VIO);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tcan4x5x_deinit(struct m_can_classdev *cdev)
|
||||
{
|
||||
struct tcan4x5x_priv *tcan4x5x = cdev_to_priv(cdev);
|
||||
|
||||
return regmap_update_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG,
|
||||
TCAN4X5X_MODE_SEL_MASK, TCAN4X5X_MODE_STANDBY);
|
||||
};
|
||||
|
||||
static int tcan4x5x_disable_wake(struct m_can_classdev *cdev)
|
||||
{
|
||||
struct tcan4x5x_priv *tcan4x5x = cdev_to_priv(cdev);
|
||||
@ -318,6 +335,14 @@ static const struct tcan4x5x_version_info
|
||||
return &tcan4x5x_versions[TCAN4X5X];
|
||||
}
|
||||
|
||||
static void tcan4x5x_get_dt_data(struct m_can_classdev *cdev)
|
||||
{
|
||||
struct tcan4x5x_priv *tcan4x5x = cdev_to_priv(cdev);
|
||||
|
||||
tcan4x5x->nwkrq_voltage_vio =
|
||||
of_property_read_bool(cdev->dev->of_node, "ti,nwkrq-voltage-vio");
|
||||
}
|
||||
|
||||
static int tcan4x5x_get_gpios(struct m_can_classdev *cdev,
|
||||
const struct tcan4x5x_version_info *version_info)
|
||||
{
|
||||
@ -359,6 +384,7 @@ static int tcan4x5x_get_gpios(struct m_can_classdev *cdev,
|
||||
|
||||
static const struct m_can_ops tcan4x5x_ops = {
|
||||
.init = tcan4x5x_init,
|
||||
.deinit = tcan4x5x_deinit,
|
||||
.read_reg = tcan4x5x_read_reg,
|
||||
.write_reg = tcan4x5x_write_reg,
|
||||
.write_fifo = tcan4x5x_write_fifo,
|
||||
@ -392,7 +418,7 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
|
||||
priv->power = NULL;
|
||||
}
|
||||
|
||||
m_can_class_get_clocks(mcan_class);
|
||||
mcan_class->cclk = devm_clk_get(mcan_class->dev, "cclk");
|
||||
if (IS_ERR(mcan_class->cclk)) {
|
||||
dev_err(&spi->dev, "no CAN clock source defined\n");
|
||||
freq = TCAN4X5X_EXT_CLK_DEF;
|
||||
@ -453,6 +479,8 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
|
||||
goto out_power;
|
||||
}
|
||||
|
||||
tcan4x5x_get_dt_data(mcan_class);
|
||||
|
||||
tcan4x5x_check_wake(priv);
|
||||
|
||||
ret = tcan4x5x_write_tcan_reg(mcan_class, TCAN4X5X_INT_EN, 0);
|
||||
|
@ -42,6 +42,8 @@ struct tcan4x5x_priv {
|
||||
|
||||
struct tcan4x5x_map_buf map_buf_rx;
|
||||
struct tcan4x5x_map_buf map_buf_tx;
|
||||
|
||||
bool nwkrq_voltage_vio;
|
||||
};
|
||||
|
||||
static inline void
|
||||
|
@ -570,7 +570,7 @@ static int sun4i_can_err(struct net_device *dev, u8 isrc, u8 status)
|
||||
else
|
||||
state = CAN_STATE_ERROR_ACTIVE;
|
||||
}
|
||||
if (skb && state != CAN_STATE_BUS_OFF) {
|
||||
if (likely(skb) && state != CAN_STATE_BUS_OFF) {
|
||||
cf->can_id |= CAN_ERR_CNT;
|
||||
cf->data[6] = txerr;
|
||||
cf->data[7] = rxerr;
|
||||
|
@ -818,7 +818,8 @@ static int kvaser_usb_init_one(struct kvaser_usb *dev, int channel)
|
||||
init_completion(&priv->stop_comp);
|
||||
init_completion(&priv->flush_comp);
|
||||
init_completion(&priv->get_busparams_comp);
|
||||
priv->can.ctrlmode_supported = CAN_CTRLMODE_CC_LEN8_DLC;
|
||||
priv->can.ctrlmode_supported = CAN_CTRLMODE_CC_LEN8_DLC |
|
||||
CAN_CTRLMODE_BERR_REPORTING;
|
||||
|
||||
priv->dev = dev;
|
||||
priv->netdev = netdev;
|
||||
|
@ -926,6 +926,42 @@ kvaser_usb_hydra_bus_status_to_can_state(const struct kvaser_usb_net_priv *priv,
|
||||
}
|
||||
}
|
||||
|
||||
static void kvaser_usb_hydra_change_state(struct kvaser_usb_net_priv *priv,
|
||||
const struct can_berr_counter *bec,
|
||||
struct can_frame *cf,
|
||||
enum can_state new_state)
|
||||
{
|
||||
struct net_device *netdev = priv->netdev;
|
||||
enum can_state old_state = priv->can.state;
|
||||
enum can_state tx_state, rx_state;
|
||||
|
||||
tx_state = (bec->txerr >= bec->rxerr) ?
|
||||
new_state : CAN_STATE_ERROR_ACTIVE;
|
||||
rx_state = (bec->txerr <= bec->rxerr) ?
|
||||
new_state : CAN_STATE_ERROR_ACTIVE;
|
||||
can_change_state(netdev, cf, tx_state, rx_state);
|
||||
|
||||
if (new_state == CAN_STATE_BUS_OFF && old_state < CAN_STATE_BUS_OFF) {
|
||||
if (priv->can.restart_ms == 0)
|
||||
kvaser_usb_hydra_send_simple_cmd_async(priv, CMD_STOP_CHIP_REQ);
|
||||
|
||||
can_bus_off(netdev);
|
||||
}
|
||||
|
||||
if (priv->can.restart_ms &&
|
||||
old_state >= CAN_STATE_BUS_OFF &&
|
||||
new_state < CAN_STATE_BUS_OFF) {
|
||||
priv->can.can_stats.restarts++;
|
||||
if (cf)
|
||||
cf->can_id |= CAN_ERR_RESTARTED;
|
||||
}
|
||||
if (cf && new_state != CAN_STATE_BUS_OFF) {
|
||||
cf->can_id |= CAN_ERR_CNT;
|
||||
cf->data[6] = bec->txerr;
|
||||
cf->data[7] = bec->rxerr;
|
||||
}
|
||||
}
|
||||
|
||||
static void kvaser_usb_hydra_update_state(struct kvaser_usb_net_priv *priv,
|
||||
u8 bus_status,
|
||||
const struct can_berr_counter *bec)
|
||||
@ -951,41 +987,11 @@ static void kvaser_usb_hydra_update_state(struct kvaser_usb_net_priv *priv,
|
||||
return;
|
||||
|
||||
skb = alloc_can_err_skb(netdev, &cf);
|
||||
if (skb) {
|
||||
enum can_state tx_state, rx_state;
|
||||
|
||||
tx_state = (bec->txerr >= bec->rxerr) ?
|
||||
new_state : CAN_STATE_ERROR_ACTIVE;
|
||||
rx_state = (bec->txerr <= bec->rxerr) ?
|
||||
new_state : CAN_STATE_ERROR_ACTIVE;
|
||||
can_change_state(netdev, cf, tx_state, rx_state);
|
||||
}
|
||||
|
||||
if (new_state == CAN_STATE_BUS_OFF && old_state < CAN_STATE_BUS_OFF) {
|
||||
if (!priv->can.restart_ms)
|
||||
kvaser_usb_hydra_send_simple_cmd_async
|
||||
(priv, CMD_STOP_CHIP_REQ);
|
||||
|
||||
can_bus_off(netdev);
|
||||
}
|
||||
|
||||
if (!skb) {
|
||||
netdev_warn(netdev, "No memory left for err_skb\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (priv->can.restart_ms &&
|
||||
old_state >= CAN_STATE_BUS_OFF &&
|
||||
new_state < CAN_STATE_BUS_OFF)
|
||||
priv->can.can_stats.restarts++;
|
||||
|
||||
if (new_state != CAN_STATE_BUS_OFF) {
|
||||
cf->can_id |= CAN_ERR_CNT;
|
||||
cf->data[6] = bec->txerr;
|
||||
cf->data[7] = bec->rxerr;
|
||||
}
|
||||
|
||||
kvaser_usb_hydra_change_state(priv, bec, cf, new_state);
|
||||
if (skb)
|
||||
netif_rx(skb);
|
||||
else
|
||||
netdev_warn(netdev, "No memory left for err_skb\n");
|
||||
}
|
||||
|
||||
static void kvaser_usb_hydra_state_event(const struct kvaser_usb *dev,
|
||||
@ -1078,9 +1084,8 @@ kvaser_usb_hydra_error_frame(struct kvaser_usb_net_priv *priv,
|
||||
{
|
||||
struct net_device *netdev = priv->netdev;
|
||||
struct net_device_stats *stats = &netdev->stats;
|
||||
struct can_frame *cf;
|
||||
struct sk_buff *skb;
|
||||
struct skb_shared_hwtstamps *shhwtstamps;
|
||||
struct can_frame *cf = NULL;
|
||||
struct sk_buff *skb = NULL;
|
||||
struct can_berr_counter bec;
|
||||
enum can_state new_state, old_state;
|
||||
u8 bus_status;
|
||||
@ -1096,51 +1101,25 @@ kvaser_usb_hydra_error_frame(struct kvaser_usb_net_priv *priv,
|
||||
kvaser_usb_hydra_bus_status_to_can_state(priv, bus_status, &bec,
|
||||
&new_state);
|
||||
|
||||
if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
|
||||
skb = alloc_can_err_skb(netdev, &cf);
|
||||
if (new_state != old_state)
|
||||
kvaser_usb_hydra_change_state(priv, &bec, cf, new_state);
|
||||
|
||||
if (new_state != old_state) {
|
||||
if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) {
|
||||
if (skb) {
|
||||
enum can_state tx_state, rx_state;
|
||||
struct skb_shared_hwtstamps *shhwtstamps = skb_hwtstamps(skb);
|
||||
|
||||
tx_state = (bec.txerr >= bec.rxerr) ?
|
||||
new_state : CAN_STATE_ERROR_ACTIVE;
|
||||
rx_state = (bec.txerr <= bec.rxerr) ?
|
||||
new_state : CAN_STATE_ERROR_ACTIVE;
|
||||
|
||||
can_change_state(netdev, cf, tx_state, rx_state);
|
||||
|
||||
if (priv->can.restart_ms &&
|
||||
old_state >= CAN_STATE_BUS_OFF &&
|
||||
new_state < CAN_STATE_BUS_OFF)
|
||||
cf->can_id |= CAN_ERR_RESTARTED;
|
||||
}
|
||||
|
||||
if (new_state == CAN_STATE_BUS_OFF) {
|
||||
if (!priv->can.restart_ms)
|
||||
kvaser_usb_hydra_send_simple_cmd_async
|
||||
(priv, CMD_STOP_CHIP_REQ);
|
||||
|
||||
can_bus_off(netdev);
|
||||
}
|
||||
}
|
||||
|
||||
if (!skb) {
|
||||
stats->rx_dropped++;
|
||||
netdev_warn(netdev, "No memory left for err_skb\n");
|
||||
return;
|
||||
}
|
||||
|
||||
shhwtstamps = skb_hwtstamps(skb);
|
||||
shhwtstamps->hwtstamp = hwtstamp;
|
||||
|
||||
cf->can_id |= CAN_ERR_BUSERROR;
|
||||
if (new_state != CAN_STATE_BUS_OFF) {
|
||||
cf->can_id |= CAN_ERR_CNT;
|
||||
cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_CNT;
|
||||
cf->data[6] = bec.txerr;
|
||||
cf->data[7] = bec.rxerr;
|
||||
}
|
||||
|
||||
netif_rx(skb);
|
||||
} else {
|
||||
stats->rx_dropped++;
|
||||
netdev_warn(netdev, "No memory left for err_skb\n");
|
||||
}
|
||||
}
|
||||
|
||||
priv->bec.txerr = bec.txerr;
|
||||
priv->bec.rxerr = bec.rxerr;
|
||||
|
@ -1120,10 +1120,8 @@ kvaser_usb_leaf_rx_error_update_can_state(struct kvaser_usb_net_priv *priv,
|
||||
static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev,
|
||||
const struct kvaser_usb_err_summary *es)
|
||||
{
|
||||
struct can_frame *cf;
|
||||
struct can_frame tmp_cf = { .can_id = CAN_ERR_FLAG,
|
||||
.len = CAN_ERR_DLC };
|
||||
struct sk_buff *skb;
|
||||
struct can_frame *cf = NULL;
|
||||
struct sk_buff *skb = NULL;
|
||||
struct net_device_stats *stats;
|
||||
struct kvaser_usb_net_priv *priv;
|
||||
struct kvaser_usb_net_leaf_priv *leaf;
|
||||
@ -1143,18 +1141,10 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev,
|
||||
if (!netif_running(priv->netdev))
|
||||
return;
|
||||
|
||||
/* Update all of the CAN interface's state and error counters before
|
||||
* trying any memory allocation that can actually fail with -ENOMEM.
|
||||
*
|
||||
* We send a temporary stack-allocated error CAN frame to
|
||||
* can_change_state() for the very same reason.
|
||||
*
|
||||
* TODO: Split can_change_state() responsibility between updating the
|
||||
* CAN interface's state and counters, and the setting up of CAN error
|
||||
* frame ID and data to userspace. Remove stack allocation afterwards.
|
||||
*/
|
||||
old_state = priv->can.state;
|
||||
kvaser_usb_leaf_rx_error_update_can_state(priv, es, &tmp_cf);
|
||||
if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING)
|
||||
skb = alloc_can_err_skb(priv->netdev, &cf);
|
||||
kvaser_usb_leaf_rx_error_update_can_state(priv, es, cf);
|
||||
new_state = priv->can.state;
|
||||
|
||||
/* If there are errors, request status updates periodically as we do
|
||||
@ -1168,13 +1158,6 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev,
|
||||
schedule_delayed_work(&leaf->chip_state_req_work,
|
||||
msecs_to_jiffies(500));
|
||||
|
||||
skb = alloc_can_err_skb(priv->netdev, &cf);
|
||||
if (!skb) {
|
||||
stats->rx_dropped++;
|
||||
return;
|
||||
}
|
||||
memcpy(cf, &tmp_cf, sizeof(*cf));
|
||||
|
||||
if (new_state != old_state) {
|
||||
if (es->status &
|
||||
(M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET)) {
|
||||
@ -1187,11 +1170,20 @@ static void kvaser_usb_leaf_rx_error(const struct kvaser_usb *dev,
|
||||
if (priv->can.restart_ms &&
|
||||
old_state == CAN_STATE_BUS_OFF &&
|
||||
new_state < CAN_STATE_BUS_OFF) {
|
||||
if (cf)
|
||||
cf->can_id |= CAN_ERR_RESTARTED;
|
||||
netif_carrier_on(priv->netdev);
|
||||
}
|
||||
}
|
||||
|
||||
if (!skb) {
|
||||
if (priv->can.ctrlmode & CAN_CTRLMODE_BERR_REPORTING) {
|
||||
stats->rx_dropped++;
|
||||
netdev_warn(priv->netdev, "No memory left for err_skb\n");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (dev->driver_info->family) {
|
||||
case KVASER_LEAF:
|
||||
if (es->leaf.error_factor) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user