Commit e794b089 authored by Jakub Kicinski's avatar Jakub Kicinski

Merge tag 'linux-can-next-for-6.7-20231005' of...

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

Marc Kleine-Budde says:

====================
pull-request: can-next 2023-10-05

The first patch is by Miquel Raynal and fixes a comment in the sja1000
driver.

Vincent Mailhol contributes 2 patches that fix W=1 compiler warnings
in the etas_es58x driver.

Jiapeng Chong's patch removes an unneeded NULL pointer check before
dev_put() in the CAN raw protocol.

A patch by Justin Stittreplaces a strncpy() by strscpy() in the
peak_pci sja1000 driver.

The next 5 patches are by me and fix the can_restart() handler and
replace BUG_ON()s in the CAN dev helpers with proper error handling.

The last 27 patches are also by me and target the at91_can driver.
First a new helper function is introduced, the at91_can driver is
cleaned up and updated to use the rx-offload helper.

* tag 'linux-can-next-for-6.7-20231005' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next: (37 commits)
  can: at91_can: switch to rx-offload implementation
  can: at91_can: at91_alloc_can_err_skb() introduce new function
  can: at91_can: at91_irq_err_line(): send error counters with state change
  can: at91_can: at91_irq_err_line(): make use of can_change_state() and can_bus_off()
  can: at91_can: at91_irq_err_line(): take reg_sr into account for bus off
  can: at91_can: at91_irq_err_line(): make use of can_state_get_by_berr_counter()
  can: at91_can: at91_irq_err(): rename to at91_irq_err_line()
  can: at91_can: at91_irq_err_frame(): move next to at91_irq_err()
  can: at91_can: at91_irq_err_frame(): call directly from IRQ handler
  can: at91_can: at91_poll_err(): increase stats even if no quota left or OOM
  can: at91_can: at91_poll_err(): fold in at91_poll_err_frame()
  can: at91_can: add CAN transceiver support
  can: at91_can: at91_open(): forward request_irq()'s return value in case or an error
  can: at91_can: at91_chip_start(): don't disable IRQs twice
  can: at91_can: at91_set_bittiming(): demote register output to debug level
  can: at91_can: rename struct at91_priv::{tx_next,tx_echo} to {tx_head,tx_tail}
  can: at91_can: at91_setup_mailboxes(): update comments
  can: at91_can: add more register definitions
  can: at91_can: MCR Register: convert to FIELD_PREP()
  can: at91_can: MSR Register: convert to FIELD_PREP()
  ...
====================

Link: https://lore.kernel.org/r/20231005195812.549776-1-mkl@pengutronix.deSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 1a489087 bf176313
...@@ -89,6 +89,7 @@ config CAN_RX_OFFLOAD ...@@ -89,6 +89,7 @@ config CAN_RX_OFFLOAD
config CAN_AT91 config CAN_AT91
tristate "Atmel AT91 onchip CAN controller" tristate "Atmel AT91 onchip CAN controller"
depends on (ARCH_AT91 || COMPILE_TEST) && HAS_IOMEM depends on (ARCH_AT91 || COMPILE_TEST) && HAS_IOMEM
select CAN_RX_OFFLOAD
help help
This is a driver for the SoC CAN controller in Atmel's AT91SAM9263 This is a driver for the SoC CAN controller in Atmel's AT91SAM9263
and AT91SAM9X5 processors. and AT91SAM9X5 processors.
......
This diff is collapsed.
...@@ -90,6 +90,28 @@ const char *can_get_state_str(const enum can_state state) ...@@ -90,6 +90,28 @@ const char *can_get_state_str(const enum can_state state)
} }
EXPORT_SYMBOL_GPL(can_get_state_str); EXPORT_SYMBOL_GPL(can_get_state_str);
static enum can_state can_state_err_to_state(u16 err)
{
if (err < CAN_ERROR_WARNING_THRESHOLD)
return CAN_STATE_ERROR_ACTIVE;
if (err < CAN_ERROR_PASSIVE_THRESHOLD)
return CAN_STATE_ERROR_WARNING;
if (err < CAN_BUS_OFF_THRESHOLD)
return CAN_STATE_ERROR_PASSIVE;
return CAN_STATE_BUS_OFF;
}
void can_state_get_by_berr_counter(const struct net_device *dev,
const struct can_berr_counter *bec,
enum can_state *tx_state,
enum can_state *rx_state)
{
*tx_state = can_state_err_to_state(bec->txerr);
*rx_state = can_state_err_to_state(bec->rxerr);
}
EXPORT_SYMBOL_GPL(can_state_get_by_berr_counter);
void can_change_state(struct net_device *dev, struct can_frame *cf, void can_change_state(struct net_device *dev, struct can_frame *cf,
enum can_state tx_state, enum can_state rx_state) enum can_state tx_state, enum can_state rx_state)
{ {
...@@ -132,7 +154,8 @@ static void can_restart(struct net_device *dev) ...@@ -132,7 +154,8 @@ static void can_restart(struct net_device *dev)
struct can_frame *cf; struct can_frame *cf;
int err; int err;
BUG_ON(netif_carrier_ok(dev)); if (netif_carrier_ok(dev))
netdev_err(dev, "Attempt to restart for bus-off recovery, but carrier is OK?\n");
/* No synchronization needed because the device is bus-off and /* No synchronization needed because the device is bus-off and
* no messages can come in or go out. * no messages can come in or go out.
...@@ -141,23 +164,21 @@ static void can_restart(struct net_device *dev) ...@@ -141,23 +164,21 @@ static void can_restart(struct net_device *dev)
/* send restart message upstream */ /* send restart message upstream */
skb = alloc_can_err_skb(dev, &cf); skb = alloc_can_err_skb(dev, &cf);
if (!skb) if (skb) {
goto restart; cf->can_id |= CAN_ERR_RESTARTED;
netif_rx(skb);
cf->can_id |= CAN_ERR_RESTARTED; }
netif_rx(skb);
restart:
netdev_dbg(dev, "restarted\n");
priv->can_stats.restarts++;
/* Now restart the device */ /* Now restart the device */
err = priv->do_set_mode(dev, CAN_MODE_START);
netif_carrier_on(dev); netif_carrier_on(dev);
if (err) err = priv->do_set_mode(dev, CAN_MODE_START);
netdev_err(dev, "Error %d during restart", err); if (err) {
netdev_err(dev, "Restart failed, error %pe\n", ERR_PTR(err));
netif_carrier_off(dev);
} else {
netdev_dbg(dev, "Restarted\n");
priv->can_stats.restarts++;
}
} }
static void can_restart_work(struct work_struct *work) static void can_restart_work(struct work_struct *work)
......
...@@ -49,7 +49,11 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev, ...@@ -49,7 +49,11 @@ int can_put_echo_skb(struct sk_buff *skb, struct net_device *dev,
{ {
struct can_priv *priv = netdev_priv(dev); struct can_priv *priv = netdev_priv(dev);
BUG_ON(idx >= priv->echo_skb_max); if (idx >= priv->echo_skb_max) {
netdev_err(dev, "%s: BUG! Trying to access can_priv::echo_skb out of bounds (%u/max %u)\n",
__func__, idx, priv->echo_skb_max);
return -EINVAL;
}
/* check flag whether this packet has to be looped back */ /* check flag whether this packet has to be looped back */
if (!(dev->flags & IFF_ECHO) || if (!(dev->flags & IFF_ECHO) ||
......
...@@ -462,7 +462,7 @@ static int peak_pciec_probe(struct pci_dev *pdev, struct net_device *dev) ...@@ -462,7 +462,7 @@ static int peak_pciec_probe(struct pci_dev *pdev, struct net_device *dev)
card->led_chip.owner = THIS_MODULE; card->led_chip.owner = THIS_MODULE;
card->led_chip.dev.parent = &pdev->dev; card->led_chip.dev.parent = &pdev->dev;
card->led_chip.algo_data = &card->i2c_bit; card->led_chip.algo_data = &card->i2c_bit;
strncpy(card->led_chip.name, "peak_i2c", strscpy(card->led_chip.name, "peak_i2c",
sizeof(card->led_chip.name)); sizeof(card->led_chip.name));
card->i2c_bit = peak_pciec_i2c_bit_ops; card->i2c_bit = peak_pciec_i2c_bit_ops;
......
...@@ -206,7 +206,7 @@ static void sja1000_start(struct net_device *dev) ...@@ -206,7 +206,7 @@ static void sja1000_start(struct net_device *dev)
{ {
struct sja1000_priv *priv = netdev_priv(dev); struct sja1000_priv *priv = netdev_priv(dev);
/* leave reset mode */ /* enter reset mode */
if (priv->can.state != CAN_STATE_STOPPED) if (priv->can.state != CAN_STATE_STOPPED)
set_reset_mode(dev); set_reset_mode(dev);
......
...@@ -2230,6 +2230,7 @@ static int es58x_probe(struct usb_interface *intf, ...@@ -2230,6 +2230,7 @@ static int es58x_probe(struct usb_interface *intf,
for (ch_idx = 0; ch_idx < es58x_dev->num_can_ch; ch_idx++) { for (ch_idx = 0; ch_idx < es58x_dev->num_can_ch; ch_idx++) {
int ret = es58x_init_netdev(es58x_dev, ch_idx); int ret = es58x_init_netdev(es58x_dev, ch_idx);
if (ret) { if (ret) {
es58x_free_netdevs(es58x_dev); es58x_free_netdevs(es58x_dev);
return ret; return ret;
......
...@@ -378,13 +378,13 @@ struct es58x_sw_version { ...@@ -378,13 +378,13 @@ struct es58x_sw_version {
/** /**
* struct es58x_hw_revision - Hardware revision number. * struct es58x_hw_revision - Hardware revision number.
* @letter: Revision letter. * @letter: Revision letter, an alphanumeric character.
* @major: Version major number, represented on three digits. * @major: Version major number, represented on three digits.
* @minor: Version minor number, represented on three digits. * @minor: Version minor number, represented on three digits.
* *
* The hardware revision uses its own format: "axxx/xxx" where 'a' is * The hardware revision uses its own format: "axxx/xxx" where 'a' is
* a letter and 'x' a digit. It can be retrieved from the product * an alphanumeric character and 'x' a digit. It can be retrieved from
* information string. * the product information string.
*/ */
struct es58x_hw_revision { struct es58x_hw_revision {
char letter; char letter;
......
...@@ -125,14 +125,28 @@ static int es58x_parse_hw_rev(struct es58x_device *es58x_dev, ...@@ -125,14 +125,28 @@ static int es58x_parse_hw_rev(struct es58x_device *es58x_dev,
* firmware version, the bootloader version and the hardware * firmware version, the bootloader version and the hardware
* revision. * revision.
* *
* If the function fails, simply emit a log message and continue * If the function fails, set the version or revision to an invalid
* because product information is not critical for the driver to * value and emit an informal message. Continue probing because the
* operate. * product information is not critical for the driver to operate.
*/ */
void es58x_parse_product_info(struct es58x_device *es58x_dev) void es58x_parse_product_info(struct es58x_device *es58x_dev)
{ {
static const struct es58x_sw_version sw_version_not_set = {
.major = -1,
.minor = -1,
.revision = -1,
};
static const struct es58x_hw_revision hw_revision_not_set = {
.letter = '\0',
.major = -1,
.minor = -1,
};
char *prod_info; char *prod_info;
es58x_dev->firmware_version = sw_version_not_set;
es58x_dev->bootloader_version = sw_version_not_set;
es58x_dev->hardware_revision = hw_revision_not_set;
prod_info = usb_cache_string(es58x_dev->udev, ES58X_PROD_INFO_IDX); prod_info = usb_cache_string(es58x_dev->udev, ES58X_PROD_INFO_IDX);
if (!prod_info) { if (!prod_info) {
dev_warn(es58x_dev->dev, dev_warn(es58x_dev->dev,
...@@ -150,29 +164,36 @@ void es58x_parse_product_info(struct es58x_device *es58x_dev) ...@@ -150,29 +164,36 @@ void es58x_parse_product_info(struct es58x_device *es58x_dev)
} }
/** /**
* es58x_sw_version_is_set() - Check if the version is a valid number. * es58x_sw_version_is_valid() - Check if the version is a valid number.
* @sw_ver: Version number of either the firmware or the bootloader. * @sw_ver: Version number of either the firmware or the bootloader.
* *
* If &es58x_sw_version.major, &es58x_sw_version.minor and * If any of the software version sub-numbers do not fit on two
* &es58x_sw_version.revision are all zero, the product string could * digits, the version is invalid, most probably because the product
* not be parsed and the version number is invalid. * string could not be parsed.
*
* Return: @true if the software version is valid, @false otherwise.
*/ */
static inline bool es58x_sw_version_is_set(struct es58x_sw_version *sw_ver) static inline bool es58x_sw_version_is_valid(struct es58x_sw_version *sw_ver)
{ {
return sw_ver->major || sw_ver->minor || sw_ver->revision; return sw_ver->major < 100 && sw_ver->minor < 100 &&
sw_ver->revision < 100;
} }
/** /**
* es58x_hw_revision_is_set() - Check if the revision is a valid number. * es58x_hw_revision_is_valid() - Check if the revision is a valid number.
* @hw_rev: Revision number of the hardware. * @hw_rev: Revision number of the hardware.
* *
* If &es58x_hw_revision.letter is the null character, the product * If &es58x_hw_revision.letter is not a alphanumeric character or if
* string could not be parsed and the hardware revision number is * any of the hardware revision sub-numbers do not fit on three
* invalid. * digits, the revision is invalid, most probably because the product
* string could not be parsed.
*
* Return: @true if the hardware revision is valid, @false otherwise.
*/ */
static inline bool es58x_hw_revision_is_set(struct es58x_hw_revision *hw_rev) static inline bool es58x_hw_revision_is_valid(struct es58x_hw_revision *hw_rev)
{ {
return hw_rev->letter != '\0'; return isalnum(hw_rev->letter) && hw_rev->major < 1000 &&
hw_rev->minor < 1000;
} }
/** /**
...@@ -197,7 +218,7 @@ static int es58x_devlink_info_get(struct devlink *devlink, ...@@ -197,7 +218,7 @@ static int es58x_devlink_info_get(struct devlink *devlink,
char buf[max(sizeof("xx.xx.xx"), sizeof("axxx/xxx"))]; char buf[max(sizeof("xx.xx.xx"), sizeof("axxx/xxx"))];
int ret = 0; int ret = 0;
if (es58x_sw_version_is_set(fw_ver)) { if (es58x_sw_version_is_valid(fw_ver)) {
snprintf(buf, sizeof(buf), "%02u.%02u.%02u", snprintf(buf, sizeof(buf), "%02u.%02u.%02u",
fw_ver->major, fw_ver->minor, fw_ver->revision); fw_ver->major, fw_ver->minor, fw_ver->revision);
ret = devlink_info_version_running_put(req, ret = devlink_info_version_running_put(req,
...@@ -207,7 +228,7 @@ static int es58x_devlink_info_get(struct devlink *devlink, ...@@ -207,7 +228,7 @@ static int es58x_devlink_info_get(struct devlink *devlink,
return ret; return ret;
} }
if (es58x_sw_version_is_set(bl_ver)) { if (es58x_sw_version_is_valid(bl_ver)) {
snprintf(buf, sizeof(buf), "%02u.%02u.%02u", snprintf(buf, sizeof(buf), "%02u.%02u.%02u",
bl_ver->major, bl_ver->minor, bl_ver->revision); bl_ver->major, bl_ver->minor, bl_ver->revision);
ret = devlink_info_version_running_put(req, ret = devlink_info_version_running_put(req,
...@@ -217,7 +238,7 @@ static int es58x_devlink_info_get(struct devlink *devlink, ...@@ -217,7 +238,7 @@ static int es58x_devlink_info_get(struct devlink *devlink,
return ret; return ret;
} }
if (es58x_hw_revision_is_set(hw_rev)) { if (es58x_hw_revision_is_valid(hw_rev)) {
snprintf(buf, sizeof(buf), "%c%03u/%03u", snprintf(buf, sizeof(buf), "%c%03u/%03u",
hw_rev->letter, hw_rev->major, hw_rev->minor); hw_rev->letter, hw_rev->major, hw_rev->minor);
ret = devlink_info_version_fixed_put(req, ret = devlink_info_version_fixed_put(req,
......
...@@ -195,6 +195,10 @@ int can_restart_now(struct net_device *dev); ...@@ -195,6 +195,10 @@ int can_restart_now(struct net_device *dev);
void can_bus_off(struct net_device *dev); void can_bus_off(struct net_device *dev);
const char *can_get_state_str(const enum can_state state); const char *can_get_state_str(const enum can_state state);
void can_state_get_by_berr_counter(const struct net_device *dev,
const struct can_berr_counter *bec,
enum can_state *tx_state,
enum can_state *rx_state);
void can_change_state(struct net_device *dev, struct can_frame *cf, void can_change_state(struct net_device *dev, struct can_frame *cf,
enum can_state tx_state, enum can_state rx_state); enum can_state tx_state, enum can_state rx_state);
......
...@@ -493,8 +493,7 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len) ...@@ -493,8 +493,7 @@ static int raw_bind(struct socket *sock, struct sockaddr *uaddr, int len)
out_put_dev: out_put_dev:
/* remove potential reference from dev_get_by_index() */ /* remove potential reference from dev_get_by_index() */
if (dev) dev_put(dev);
dev_put(dev);
out: out:
release_sock(sk); release_sock(sk);
rtnl_unlock(); rtnl_unlock();
......
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