diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c index 80c46ad4cee4..ad0a7e8c2c2b 100644 --- a/drivers/net/can/flexcan.c +++ b/drivers/net/can/flexcan.c @@ -592,13 +592,12 @@ static int flexcan_poll_state(struct net_device *dev, u32 reg_esr) rx_state = unlikely(reg_esr & FLEXCAN_ESR_RX_WRN) ? CAN_STATE_ERROR_WARNING : CAN_STATE_ERROR_ACTIVE; new_state = max(tx_state, rx_state); - } else if (unlikely(flt == FLEXCAN_ESR_FLT_CONF_PASSIVE)) { + } else { __flexcan_get_berr_counter(dev, &bec); - new_state = CAN_STATE_ERROR_PASSIVE; + new_state = flt == FLEXCAN_ESR_FLT_CONF_PASSIVE ? + CAN_STATE_ERROR_PASSIVE : CAN_STATE_BUS_OFF; rx_state = bec.rxerr >= bec.txerr ? new_state : 0; tx_state = bec.rxerr <= bec.txerr ? new_state : 0; - } else { - new_state = CAN_STATE_BUS_OFF; } /* state hasn't changed */ @@ -1158,12 +1157,19 @@ static int flexcan_probe(struct platform_device *pdev) const struct flexcan_devtype_data *devtype_data; struct net_device *dev; struct flexcan_priv *priv; + struct regulator *reg_xceiver; struct resource *mem; struct clk *clk_ipg = NULL, *clk_per = NULL; void __iomem *base; int err, irq; u32 clock_freq = 0; + reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver"); + if (PTR_ERR(reg_xceiver) == -EPROBE_DEFER) + return -EPROBE_DEFER; + else if (IS_ERR(reg_xceiver)) + reg_xceiver = NULL; + if (pdev->dev.of_node) of_property_read_u32(pdev->dev.of_node, "clock-frequency", &clock_freq); @@ -1224,9 +1230,7 @@ static int flexcan_probe(struct platform_device *pdev) priv->pdata = dev_get_platdata(&pdev->dev); priv->devtype_data = devtype_data; - priv->reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver"); - if (IS_ERR(priv->reg_xceiver)) - priv->reg_xceiver = NULL; + priv->reg_xceiver = reg_xceiver; netif_napi_add(dev, &priv->napi, flexcan_poll, FLEXCAN_NAPI_WEIGHT); diff --git a/drivers/net/can/usb/gs_usb.c b/drivers/net/can/usb/gs_usb.c index 009acc8641fc..8b4d3e6875eb 100644 --- a/drivers/net/can/usb/gs_usb.c +++ b/drivers/net/can/usb/gs_usb.c @@ -901,6 +901,8 @@ static int gs_usb_probe(struct usb_interface *intf, const struct usb_device_id * } dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; init_usb_anchor(&dev->rx_submitted); atomic_set(&dev->active_channels, 0); diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c index e97a08ce0b90..57611fd91229 100644 --- a/drivers/net/can/usb/kvaser_usb.c +++ b/drivers/net/can/usb/kvaser_usb.c @@ -25,7 +25,6 @@ #include #include -#define MAX_TX_URBS 16 #define MAX_RX_URBS 4 #define START_TIMEOUT 1000 /* msecs */ #define STOP_TIMEOUT 1000 /* msecs */ @@ -443,6 +442,7 @@ struct kvaser_usb_error_summary { }; }; +/* Context for an outstanding, not yet ACKed, transmission */ struct kvaser_usb_tx_urb_context { struct kvaser_usb_net_priv *priv; u32 echo_index; @@ -456,8 +456,13 @@ struct kvaser_usb { struct usb_endpoint_descriptor *bulk_in, *bulk_out; struct usb_anchor rx_submitted; + /* @max_tx_urbs: Firmware-reported maximum number of oustanding, + * not yet ACKed, transmissions on this device. This value is + * also used as a sentinel for marking free tx contexts. + */ u32 fw_version; unsigned int nchannels; + unsigned int max_tx_urbs; enum kvaser_usb_family family; bool rxinitdone; @@ -467,19 +472,18 @@ struct kvaser_usb { struct kvaser_usb_net_priv { struct can_priv can; - - spinlock_t tx_contexts_lock; - int active_tx_contexts; - struct kvaser_usb_tx_urb_context tx_contexts[MAX_TX_URBS]; - - struct usb_anchor tx_submitted; - struct completion start_comp, stop_comp; + struct can_berr_counter bec; struct kvaser_usb *dev; struct net_device *netdev; int channel; - struct can_berr_counter bec; + struct completion start_comp, stop_comp; + struct usb_anchor tx_submitted; + + spinlock_t tx_contexts_lock; + int active_tx_contexts; + struct kvaser_usb_tx_urb_context tx_contexts[]; }; static const struct usb_device_id kvaser_usb_table[] = { @@ -592,8 +596,8 @@ static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id, * for further details. */ if (tmp->len == 0) { - pos = round_up(pos, - dev->bulk_in->wMaxPacketSize); + pos = round_up(pos, le16_to_cpu(dev->bulk_in-> + wMaxPacketSize)); continue; } @@ -657,9 +661,13 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev) switch (dev->family) { case KVASER_LEAF: dev->fw_version = le32_to_cpu(msg.u.leaf.softinfo.fw_version); + dev->max_tx_urbs = + le16_to_cpu(msg.u.leaf.softinfo.max_outstanding_tx); break; case KVASER_USBCAN: dev->fw_version = le32_to_cpu(msg.u.usbcan.softinfo.fw_version); + dev->max_tx_urbs = + le16_to_cpu(msg.u.usbcan.softinfo.max_outstanding_tx); break; } @@ -715,7 +723,7 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev, stats = &priv->netdev->stats; - context = &priv->tx_contexts[tid % MAX_TX_URBS]; + context = &priv->tx_contexts[tid % dev->max_tx_urbs]; /* Sometimes the state change doesn't come after a bus-off event */ if (priv->can.restart_ms && @@ -744,7 +752,7 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev, spin_lock_irqsave(&priv->tx_contexts_lock, flags); can_get_echo_skb(priv->netdev, context->echo_index); - context->echo_index = MAX_TX_URBS; + context->echo_index = dev->max_tx_urbs; --priv->active_tx_contexts; netif_wake_queue(priv->netdev); @@ -1329,7 +1337,8 @@ static void kvaser_usb_read_bulk_callback(struct urb *urb) * number of events in case of a heavy rx load on the bus. */ if (msg->len == 0) { - pos = round_up(pos, dev->bulk_in->wMaxPacketSize); + pos = round_up(pos, le16_to_cpu(dev->bulk_in-> + wMaxPacketSize)); continue; } @@ -1512,11 +1521,13 @@ static int kvaser_usb_open(struct net_device *netdev) static void kvaser_usb_reset_tx_urb_contexts(struct kvaser_usb_net_priv *priv) { - int i; + int i, max_tx_urbs; + + max_tx_urbs = priv->dev->max_tx_urbs; priv->active_tx_contexts = 0; - for (i = 0; i < MAX_TX_URBS; i++) - priv->tx_contexts[i].echo_index = MAX_TX_URBS; + for (i = 0; i < max_tx_urbs; i++) + priv->tx_contexts[i].echo_index = max_tx_urbs; } /* This method might sleep. Do not call it in the atomic context @@ -1702,14 +1713,14 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, *msg_tx_can_flags |= MSG_FLAG_REMOTE_FRAME; spin_lock_irqsave(&priv->tx_contexts_lock, flags); - for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) { - if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) { + for (i = 0; i < dev->max_tx_urbs; i++) { + if (priv->tx_contexts[i].echo_index == dev->max_tx_urbs) { context = &priv->tx_contexts[i]; context->echo_index = i; can_put_echo_skb(skb, netdev, context->echo_index); ++priv->active_tx_contexts; - if (priv->active_tx_contexts >= MAX_TX_URBS) + if (priv->active_tx_contexts >= dev->max_tx_urbs) netif_stop_queue(netdev); break; @@ -1743,7 +1754,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb, spin_lock_irqsave(&priv->tx_contexts_lock, flags); can_free_echo_skb(netdev, context->echo_index); - context->echo_index = MAX_TX_URBS; + context->echo_index = dev->max_tx_urbs; --priv->active_tx_contexts; netif_wake_queue(netdev); @@ -1881,7 +1892,9 @@ static int kvaser_usb_init_one(struct usb_interface *intf, if (err) return err; - netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS); + netdev = alloc_candev(sizeof(*priv) + + dev->max_tx_urbs * sizeof(*priv->tx_contexts), + dev->max_tx_urbs); if (!netdev) { dev_err(&intf->dev, "Cannot alloc candev\n"); return -ENOMEM; @@ -2009,6 +2022,13 @@ static int kvaser_usb_probe(struct usb_interface *intf, return err; } + dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n", + ((dev->fw_version >> 24) & 0xff), + ((dev->fw_version >> 16) & 0xff), + (dev->fw_version & 0xffff)); + + dev_dbg(&intf->dev, "Max oustanding tx = %d URBs\n", dev->max_tx_urbs); + err = kvaser_usb_get_card_info(dev); if (err) { dev_err(&intf->dev, @@ -2016,11 +2036,6 @@ static int kvaser_usb_probe(struct usb_interface *intf, return err; } - dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n", - ((dev->fw_version >> 24) & 0xff), - ((dev->fw_version >> 16) & 0xff), - (dev->fw_version & 0xffff)); - for (i = 0; i < dev->nchannels; i++) { err = kvaser_usb_init_one(intf, id, i); if (err) { diff --git a/drivers/net/can/usb/peak_usb/pcan_ucan.h b/drivers/net/can/usb/peak_usb/pcan_ucan.h index 1ba7c25002e1..e8fc4952c6b0 100644 --- a/drivers/net/can/usb/peak_usb/pcan_ucan.h +++ b/drivers/net/can/usb/peak_usb/pcan_ucan.h @@ -26,8 +26,8 @@ #define PUCAN_CMD_FILTER_STD 0x008 #define PUCAN_CMD_TX_ABORT 0x009 #define PUCAN_CMD_WR_ERR_CNT 0x00a -#define PUCAN_CMD_RX_FRAME_ENABLE 0x00b -#define PUCAN_CMD_RX_FRAME_DISABLE 0x00c +#define PUCAN_CMD_SET_EN_OPTION 0x00b +#define PUCAN_CMD_CLR_DIS_OPTION 0x00c #define PUCAN_CMD_END_OF_COLLECTION 0x3ff /* uCAN received messages list */ @@ -101,14 +101,15 @@ struct __packed pucan_wr_err_cnt { u16 unused; }; -/* uCAN RX_FRAME_ENABLE command fields */ -#define PUCAN_FLTEXT_ERROR 0x0001 -#define PUCAN_FLTEXT_BUSLOAD 0x0002 +/* uCAN SET_EN/CLR_DIS _OPTION command fields */ +#define PUCAN_OPTION_ERROR 0x0001 +#define PUCAN_OPTION_BUSLOAD 0x0002 +#define PUCAN_OPTION_CANDFDISO 0x0004 -struct __packed pucan_filter_ext { +struct __packed pucan_options { __le16 opcode_channel; - __le16 ext_mask; + __le16 options; u32 unused; }; diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c index 0bac0f14edc3..a9221ad9f1a0 100644 --- a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c +++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c @@ -110,13 +110,13 @@ struct __packed pcan_ufd_led { u8 unused[5]; }; -/* Extended usage of uCAN commands CMD_RX_FRAME_xxxABLE for PCAN-USB Pro FD */ +/* Extended usage of uCAN commands CMD_xxx_xx_OPTION for PCAN-USB Pro FD */ #define PCAN_UFD_FLTEXT_CALIBRATION 0x8000 -struct __packed pcan_ufd_filter_ext { +struct __packed pcan_ufd_options { __le16 opcode_channel; - __le16 ext_mask; + __le16 ucan_mask; u16 unused; __le16 usb_mask; }; @@ -251,6 +251,27 @@ static int pcan_usb_fd_build_restart_cmd(struct peak_usb_device *dev, u8 *buf) /* moves the pointer forward */ pc += sizeof(struct pucan_wr_err_cnt); + /* add command to switch from ISO to non-ISO mode, if fw allows it */ + if (dev->can.ctrlmode_supported & CAN_CTRLMODE_FD_NON_ISO) { + struct pucan_options *puo = (struct pucan_options *)pc; + + puo->opcode_channel = + (dev->can.ctrlmode & CAN_CTRLMODE_FD_NON_ISO) ? + pucan_cmd_opcode_channel(dev, + PUCAN_CMD_CLR_DIS_OPTION) : + pucan_cmd_opcode_channel(dev, PUCAN_CMD_SET_EN_OPTION); + + puo->options = cpu_to_le16(PUCAN_OPTION_CANDFDISO); + + /* to be sure that no other extended bits will be taken into + * account + */ + puo->unused = 0; + + /* moves the pointer forward */ + pc += sizeof(struct pucan_options); + } + /* next, go back to operational mode */ cmd = (struct pucan_command *)pc; cmd->opcode_channel = pucan_cmd_opcode_channel(dev, @@ -321,21 +342,21 @@ static int pcan_usb_fd_set_filter_std(struct peak_usb_device *dev, int idx, return pcan_usb_fd_send_cmd(dev, cmd); } -/* set/unset notifications filter: +/* set/unset options * - * onoff sets(1)/unset(0) notifications - * mask each bit defines a kind of notification to set/unset + * onoff set(1)/unset(0) options + * mask each bit defines a kind of options to set/unset */ -static int pcan_usb_fd_set_filter_ext(struct peak_usb_device *dev, - bool onoff, u16 ext_mask, u16 usb_mask) +static int pcan_usb_fd_set_options(struct peak_usb_device *dev, + bool onoff, u16 ucan_mask, u16 usb_mask) { - struct pcan_ufd_filter_ext *cmd = pcan_usb_fd_cmd_buffer(dev); + struct pcan_ufd_options *cmd = pcan_usb_fd_cmd_buffer(dev); cmd->opcode_channel = pucan_cmd_opcode_channel(dev, - (onoff) ? PUCAN_CMD_RX_FRAME_ENABLE : - PUCAN_CMD_RX_FRAME_DISABLE); + (onoff) ? PUCAN_CMD_SET_EN_OPTION : + PUCAN_CMD_CLR_DIS_OPTION); - cmd->ext_mask = cpu_to_le16(ext_mask); + cmd->ucan_mask = cpu_to_le16(ucan_mask); cmd->usb_mask = cpu_to_le16(usb_mask); /* send the command */ @@ -770,9 +791,9 @@ static int pcan_usb_fd_start(struct peak_usb_device *dev) &pcan_usb_pro_fd); /* enable USB calibration messages */ - err = pcan_usb_fd_set_filter_ext(dev, 1, - PUCAN_FLTEXT_ERROR, - PCAN_UFD_FLTEXT_CALIBRATION); + err = pcan_usb_fd_set_options(dev, 1, + PUCAN_OPTION_ERROR, + PCAN_UFD_FLTEXT_CALIBRATION); } pdev->usb_if->dev_opened_count++; @@ -806,9 +827,9 @@ static int pcan_usb_fd_stop(struct peak_usb_device *dev) /* turn off special msgs for that interface if no other dev opened */ if (pdev->usb_if->dev_opened_count == 1) - pcan_usb_fd_set_filter_ext(dev, 0, - PUCAN_FLTEXT_ERROR, - PCAN_UFD_FLTEXT_CALIBRATION); + pcan_usb_fd_set_options(dev, 0, + PUCAN_OPTION_ERROR, + PCAN_UFD_FLTEXT_CALIBRATION); pdev->usb_if->dev_opened_count--; return 0; @@ -860,8 +881,14 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev) pdev->usb_if->fw_info.fw_version[2], dev->adapter->ctrl_count); - /* the currently supported hw is non-ISO */ - dev->can.ctrlmode = CAN_CTRLMODE_FD_NON_ISO; + /* check for ability to switch between ISO/non-ISO modes */ + if (pdev->usb_if->fw_info.fw_version[0] >= 2) { + /* firmware >= 2.x supports ISO/non-ISO switching */ + dev->can.ctrlmode_supported |= CAN_CTRLMODE_FD_NON_ISO; + } else { + /* firmware < 2.x only supports fixed(!) non-ISO */ + dev->can.ctrlmode |= CAN_CTRLMODE_FD_NON_ISO; + } /* tell the hardware the can driver is running */ err = pcan_usb_fd_drv_loaded(dev, 1); @@ -937,9 +964,9 @@ static void pcan_usb_fd_exit(struct peak_usb_device *dev) if (dev->ctrl_idx == 0) { /* turn off calibration message if any device were opened */ if (pdev->usb_if->dev_opened_count > 0) - pcan_usb_fd_set_filter_ext(dev, 0, - PUCAN_FLTEXT_ERROR, - PCAN_UFD_FLTEXT_CALIBRATION); + pcan_usb_fd_set_options(dev, 0, + PUCAN_OPTION_ERROR, + PCAN_UFD_FLTEXT_CALIBRATION); /* tell USB adapter that the driver is being unloaded */ pcan_usb_fd_drv_loaded(dev, 0);