Skip to content

Commit 542d0f6

Browse files
committed
Merge tag 'linux-can-fixes-for-5.5-20200102' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can
Marc Kleine-Budde says: ==================== pull-request: can 2020-01-02 this is a pull request of 9 patches for net/master. The first 5 patches target all the tcan4x5x driver. The first 3 patches of them are by Dan Murphy and Sean Nyekjaer and improve the device initialization (power on, reset and get device out of standby before register access). The next patch is by Dan Murphy and disables the INH pin device-state if the GPIO is unavailable. The last patch for the tcan4x5x driver is by Gustavo A. R. Silva and fixes an inconsistent PTR_ERR check in the tcan4x5x_parse_config() function. The next patch is by Oliver Hartkopp and targets the generic CAN device infrastructure. It ensures that an initialized headroom in outgoing CAN sk_buffs (e.g. if injected by AF_PACKET). The last 2 patches are by Johan Hovold and fix the kvaser_usb and gs_usb drivers by always using the current alternate setting not blindly the first one. ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents c72a0bc + 2d77bd6 commit 542d0f6

File tree

6 files changed

+101
-25
lines changed

6 files changed

+101
-25
lines changed

drivers/net/can/m_can/tcan4x5x.c

Lines changed: 53 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
#define TCAN4X5X_MODE_NORMAL BIT(7)
103103

104104
#define TCAN4X5X_DISABLE_WAKE_MSK (BIT(31) | BIT(30))
105+
#define TCAN4X5X_DISABLE_INH_MSK BIT(9)
105106

106107
#define TCAN4X5X_SW_RESET BIT(2)
107108

@@ -166,6 +167,28 @@ static void tcan4x5x_check_wake(struct tcan4x5x_priv *priv)
166167
}
167168
}
168169

170+
static int tcan4x5x_reset(struct tcan4x5x_priv *priv)
171+
{
172+
int ret = 0;
173+
174+
if (priv->reset_gpio) {
175+
gpiod_set_value(priv->reset_gpio, 1);
176+
177+
/* tpulse_width minimum 30us */
178+
usleep_range(30, 100);
179+
gpiod_set_value(priv->reset_gpio, 0);
180+
} else {
181+
ret = regmap_write(priv->regmap, TCAN4X5X_CONFIG,
182+
TCAN4X5X_SW_RESET);
183+
if (ret)
184+
return ret;
185+
}
186+
187+
usleep_range(700, 1000);
188+
189+
return ret;
190+
}
191+
169192
static int regmap_spi_gather_write(void *context, const void *reg,
170193
size_t reg_len, const void *val,
171194
size_t val_len)
@@ -348,14 +371,23 @@ static int tcan4x5x_disable_wake(struct m_can_classdev *cdev)
348371
TCAN4X5X_DISABLE_WAKE_MSK, 0x00);
349372
}
350373

374+
static int tcan4x5x_disable_state(struct m_can_classdev *cdev)
375+
{
376+
struct tcan4x5x_priv *tcan4x5x = cdev->device_data;
377+
378+
return regmap_update_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG,
379+
TCAN4X5X_DISABLE_INH_MSK, 0x01);
380+
}
381+
351382
static int tcan4x5x_parse_config(struct m_can_classdev *cdev)
352383
{
353384
struct tcan4x5x_priv *tcan4x5x = cdev->device_data;
385+
int ret;
354386

355387
tcan4x5x->device_wake_gpio = devm_gpiod_get(cdev->dev, "device-wake",
356388
GPIOD_OUT_HIGH);
357389
if (IS_ERR(tcan4x5x->device_wake_gpio)) {
358-
if (PTR_ERR(tcan4x5x->power) == -EPROBE_DEFER)
390+
if (PTR_ERR(tcan4x5x->device_wake_gpio) == -EPROBE_DEFER)
359391
return -EPROBE_DEFER;
360392

361393
tcan4x5x_disable_wake(cdev);
@@ -366,18 +398,17 @@ static int tcan4x5x_parse_config(struct m_can_classdev *cdev)
366398
if (IS_ERR(tcan4x5x->reset_gpio))
367399
tcan4x5x->reset_gpio = NULL;
368400

369-
usleep_range(700, 1000);
401+
ret = tcan4x5x_reset(tcan4x5x);
402+
if (ret)
403+
return ret;
370404

371405
tcan4x5x->device_state_gpio = devm_gpiod_get_optional(cdev->dev,
372406
"device-state",
373407
GPIOD_IN);
374-
if (IS_ERR(tcan4x5x->device_state_gpio))
408+
if (IS_ERR(tcan4x5x->device_state_gpio)) {
375409
tcan4x5x->device_state_gpio = NULL;
376-
377-
tcan4x5x->power = devm_regulator_get_optional(cdev->dev,
378-
"vsup");
379-
if (PTR_ERR(tcan4x5x->power) == -EPROBE_DEFER)
380-
return -EPROBE_DEFER;
410+
tcan4x5x_disable_state(cdev);
411+
}
381412

382413
return 0;
383414
}
@@ -412,6 +443,12 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
412443
if (!priv)
413444
return -ENOMEM;
414445

446+
priv->power = devm_regulator_get_optional(&spi->dev, "vsup");
447+
if (PTR_ERR(priv->power) == -EPROBE_DEFER)
448+
return -EPROBE_DEFER;
449+
else
450+
priv->power = NULL;
451+
415452
mcan_class->device_data = priv;
416453

417454
m_can_class_get_clocks(mcan_class);
@@ -451,11 +488,17 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
451488
priv->regmap = devm_regmap_init(&spi->dev, &tcan4x5x_bus,
452489
&spi->dev, &tcan4x5x_regmap);
453490

454-
ret = tcan4x5x_parse_config(mcan_class);
491+
ret = tcan4x5x_power_enable(priv->power, 1);
455492
if (ret)
456493
goto out_clk;
457494

458-
tcan4x5x_power_enable(priv->power, 1);
495+
ret = tcan4x5x_parse_config(mcan_class);
496+
if (ret)
497+
goto out_power;
498+
499+
ret = tcan4x5x_init(mcan_class);
500+
if (ret)
501+
goto out_power;
459502

460503
ret = m_can_class_register(mcan_class);
461504
if (ret)

drivers/net/can/mscan/mscan.c

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -381,13 +381,12 @@ static int mscan_rx_poll(struct napi_struct *napi, int quota)
381381
struct net_device *dev = napi->dev;
382382
struct mscan_regs __iomem *regs = priv->reg_base;
383383
struct net_device_stats *stats = &dev->stats;
384-
int npackets = 0;
385-
int ret = 1;
384+
int work_done = 0;
386385
struct sk_buff *skb;
387386
struct can_frame *frame;
388387
u8 canrflg;
389388

390-
while (npackets < quota) {
389+
while (work_done < quota) {
391390
canrflg = in_8(&regs->canrflg);
392391
if (!(canrflg & (MSCAN_RXF | MSCAN_ERR_IF)))
393392
break;
@@ -408,18 +407,18 @@ static int mscan_rx_poll(struct napi_struct *napi, int quota)
408407

409408
stats->rx_packets++;
410409
stats->rx_bytes += frame->can_dlc;
411-
npackets++;
410+
work_done++;
412411
netif_receive_skb(skb);
413412
}
414413

415-
if (!(in_8(&regs->canrflg) & (MSCAN_RXF | MSCAN_ERR_IF))) {
416-
napi_complete(&priv->napi);
417-
clear_bit(F_RX_PROGRESS, &priv->flags);
418-
if (priv->can.state < CAN_STATE_BUS_OFF)
419-
out_8(&regs->canrier, priv->shadow_canrier);
420-
ret = 0;
414+
if (work_done < quota) {
415+
if (likely(napi_complete_done(&priv->napi, work_done))) {
416+
clear_bit(F_RX_PROGRESS, &priv->flags);
417+
if (priv->can.state < CAN_STATE_BUS_OFF)
418+
out_8(&regs->canrier, priv->shadow_canrier);
419+
}
421420
}
422-
return ret;
421+
return work_done;
423422
}
424423

425424
static irqreturn_t mscan_isr(int irq, void *dev_id)

drivers/net/can/usb/gs_usb.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -918,7 +918,7 @@ static int gs_usb_probe(struct usb_interface *intf,
918918
GS_USB_BREQ_HOST_FORMAT,
919919
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
920920
1,
921-
intf->altsetting[0].desc.bInterfaceNumber,
921+
intf->cur_altsetting->desc.bInterfaceNumber,
922922
hconf,
923923
sizeof(*hconf),
924924
1000);
@@ -941,7 +941,7 @@ static int gs_usb_probe(struct usb_interface *intf,
941941
GS_USB_BREQ_DEVICE_CONFIG,
942942
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
943943
1,
944-
intf->altsetting[0].desc.bInterfaceNumber,
944+
intf->cur_altsetting->desc.bInterfaceNumber,
945945
dconf,
946946
sizeof(*dconf),
947947
1000);

drivers/net/can/usb/kvaser_usb/kvaser_usb_hydra.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1590,7 +1590,7 @@ static int kvaser_usb_hydra_setup_endpoints(struct kvaser_usb *dev)
15901590
struct usb_endpoint_descriptor *ep;
15911591
int i;
15921592

1593-
iface_desc = &dev->intf->altsetting[0];
1593+
iface_desc = dev->intf->cur_altsetting;
15941594

15951595
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
15961596
ep = &iface_desc->endpoint[i].desc;

drivers/net/can/usb/kvaser_usb/kvaser_usb_leaf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1310,7 +1310,7 @@ static int kvaser_usb_leaf_setup_endpoints(struct kvaser_usb *dev)
13101310
struct usb_endpoint_descriptor *endpoint;
13111311
int i;
13121312

1313-
iface_desc = &dev->intf->altsetting[0];
1313+
iface_desc = dev->intf->cur_altsetting;
13141314

13151315
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
13161316
endpoint = &iface_desc->endpoint[i].desc;

include/linux/can/dev.h

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <linux/can/error.h>
1919
#include <linux/can/led.h>
2020
#include <linux/can/netlink.h>
21+
#include <linux/can/skb.h>
2122
#include <linux/netdevice.h>
2223

2324
/*
@@ -91,6 +92,36 @@ struct can_priv {
9192
#define get_can_dlc(i) (min_t(__u8, (i), CAN_MAX_DLC))
9293
#define get_canfd_dlc(i) (min_t(__u8, (i), CANFD_MAX_DLC))
9394

95+
/* Check for outgoing skbs that have not been created by the CAN subsystem */
96+
static inline bool can_skb_headroom_valid(struct net_device *dev,
97+
struct sk_buff *skb)
98+
{
99+
/* af_packet creates a headroom of HH_DATA_MOD bytes which is fine */
100+
if (WARN_ON_ONCE(skb_headroom(skb) < sizeof(struct can_skb_priv)))
101+
return false;
102+
103+
/* af_packet does not apply CAN skb specific settings */
104+
if (skb->ip_summed == CHECKSUM_NONE) {
105+
/* init headroom */
106+
can_skb_prv(skb)->ifindex = dev->ifindex;
107+
can_skb_prv(skb)->skbcnt = 0;
108+
109+
skb->ip_summed = CHECKSUM_UNNECESSARY;
110+
111+
/* preform proper loopback on capable devices */
112+
if (dev->flags & IFF_ECHO)
113+
skb->pkt_type = PACKET_LOOPBACK;
114+
else
115+
skb->pkt_type = PACKET_HOST;
116+
117+
skb_reset_mac_header(skb);
118+
skb_reset_network_header(skb);
119+
skb_reset_transport_header(skb);
120+
}
121+
122+
return true;
123+
}
124+
94125
/* Drop a given socketbuffer if it does not contain a valid CAN frame. */
95126
static inline bool can_dropped_invalid_skb(struct net_device *dev,
96127
struct sk_buff *skb)
@@ -108,6 +139,9 @@ static inline bool can_dropped_invalid_skb(struct net_device *dev,
108139
} else
109140
goto inval_skb;
110141

142+
if (!can_skb_headroom_valid(dev, skb))
143+
goto inval_skb;
144+
111145
return false;
112146

113147
inval_skb:

0 commit comments

Comments
 (0)