Commit a00ebc46 authored by David S. Miller's avatar David S. Miller

Merge tag 'linux-can-next-for-4.11-20170124' of...

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

Marc Kleine-Budde says:

====================
pull-request: can-next 2017-01-24

this is a pull request of 4 patches for net-next/master.

The first patch by Oliver Hartkopp adds a netlink API to configure the
interface termination of a CAN card. The next two patches are by me and
add a netlink API to query and configure CAN interfaces that only
support fixed bitrates. The last patch by Colin Ian King simplifies the
return path in the softing_cs driver's softingcs_probe() function.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 45ce0fd1 1e9bbb9b
......@@ -279,25 +279,45 @@ static int can_fixup_bittiming(struct net_device *dev, struct can_bittiming *bt,
return 0;
}
/* Checks the validity of predefined bitrate settings */
static int can_validate_bitrate(struct net_device *dev, struct can_bittiming *bt,
const u32 *bitrate_const,
const unsigned int bitrate_const_cnt)
{
struct can_priv *priv = netdev_priv(dev);
unsigned int i;
for (i = 0; i < bitrate_const_cnt; i++) {
if (bt->bitrate == bitrate_const[i])
break;
}
if (i >= priv->bitrate_const_cnt)
return -EINVAL;
return 0;
}
static int can_get_bittiming(struct net_device *dev, struct can_bittiming *bt,
const struct can_bittiming_const *btc)
const struct can_bittiming_const *btc,
const u32 *bitrate_const,
const unsigned int bitrate_const_cnt)
{
int err;
/* Check if the CAN device has bit-timing parameters */
if (!btc)
return -EOPNOTSUPP;
/*
* Depending on the given can_bittiming parameter structure the CAN
* timing parameters are calculated based on the provided bitrate OR
* alternatively the CAN timing parameters (tq, prop_seg, etc.) are
* provided directly which are then checked and fixed up.
*/
if (!bt->tq && bt->bitrate)
if (!bt->tq && bt->bitrate && btc)
err = can_calc_bittiming(dev, bt, btc);
else if (bt->tq && !bt->bitrate)
else if (bt->tq && !bt->bitrate && btc)
err = can_fixup_bittiming(dev, bt, btc);
else if (!bt->tq && bt->bitrate && bitrate_const)
err = can_validate_bitrate(dev, bt, bitrate_const,
bitrate_const_cnt);
else
err = -EINVAL;
......@@ -872,8 +892,20 @@ static int can_changelink(struct net_device *dev,
/* Do not allow changing bittiming while running */
if (dev->flags & IFF_UP)
return -EBUSY;
/* Calculate bittiming parameters based on
* bittiming_const if set, otherwise pass bitrate
* directly via do_set_bitrate(). Bail out if neither
* is given.
*/
if (!priv->bittiming_const && !priv->do_set_bittiming)
return -EOPNOTSUPP;
memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
err = can_get_bittiming(dev, &bt, priv->bittiming_const);
err = can_get_bittiming(dev, &bt,
priv->bittiming_const,
priv->bitrate_const,
priv->bitrate_const_cnt);
if (err)
return err;
memcpy(&priv->bittiming, &bt, sizeof(bt));
......@@ -943,9 +975,21 @@ static int can_changelink(struct net_device *dev,
/* Do not allow changing bittiming while running */
if (dev->flags & IFF_UP)
return -EBUSY;
/* Calculate bittiming parameters based on
* data_bittiming_const if set, otherwise pass bitrate
* directly via do_set_bitrate(). Bail out if neither
* is given.
*/
if (!priv->data_bittiming_const && !priv->do_set_data_bittiming)
return -EOPNOTSUPP;
memcpy(&dbt, nla_data(data[IFLA_CAN_DATA_BITTIMING]),
sizeof(dbt));
err = can_get_bittiming(dev, &dbt, priv->data_bittiming_const);
err = can_get_bittiming(dev, &dbt,
priv->data_bittiming_const,
priv->data_bitrate_const,
priv->data_bitrate_const_cnt);
if (err)
return err;
memcpy(&priv->data_bittiming, &dbt, sizeof(dbt));
......@@ -958,6 +1002,30 @@ static int can_changelink(struct net_device *dev,
}
}
if (data[IFLA_CAN_TERMINATION]) {
const u16 termval = nla_get_u16(data[IFLA_CAN_TERMINATION]);
const unsigned int num_term = priv->termination_const_cnt;
unsigned int i;
if (!priv->do_set_termination)
return -EOPNOTSUPP;
/* check whether given value is supported by the interface */
for (i = 0; i < num_term; i++) {
if (termval == priv->termination_const[i])
break;
}
if (i >= num_term)
return -EINVAL;
/* Finally, set the termination value */
err = priv->do_set_termination(dev, termval);
if (err)
return err;
priv->termination = termval;
}
return 0;
}
......@@ -980,6 +1048,17 @@ static size_t can_get_size(const struct net_device *dev)
size += nla_total_size(sizeof(struct can_bittiming));
if (priv->data_bittiming_const) /* IFLA_CAN_DATA_BITTIMING_CONST */
size += nla_total_size(sizeof(struct can_bittiming_const));
if (priv->termination_const) {
size += nla_total_size(sizeof(priv->termination)); /* IFLA_CAN_TERMINATION */
size += nla_total_size(sizeof(*priv->termination_const) * /* IFLA_CAN_TERMINATION_CONST */
priv->termination_const_cnt);
}
if (priv->bitrate_const) /* IFLA_CAN_BITRATE_CONST */
size += nla_total_size(sizeof(*priv->bitrate_const) *
priv->bitrate_const_cnt);
if (priv->data_bitrate_const) /* IFLA_CAN_DATA_BITRATE_CONST */
size += nla_total_size(sizeof(*priv->data_bitrate_const) *
priv->data_bitrate_const_cnt);
return size;
}
......@@ -1018,7 +1097,28 @@ static int can_fill_info(struct sk_buff *skb, const struct net_device *dev)
(priv->data_bittiming_const &&
nla_put(skb, IFLA_CAN_DATA_BITTIMING_CONST,
sizeof(*priv->data_bittiming_const),
priv->data_bittiming_const)))
priv->data_bittiming_const)) ||
(priv->termination_const &&
(nla_put_u16(skb, IFLA_CAN_TERMINATION, priv->termination) ||
nla_put(skb, IFLA_CAN_TERMINATION_CONST,
sizeof(*priv->termination_const) *
priv->termination_const_cnt,
priv->termination_const))) ||
(priv->bitrate_const &&
nla_put(skb, IFLA_CAN_BITRATE_CONST,
sizeof(*priv->bitrate_const) *
priv->bitrate_const_cnt,
priv->bitrate_const)) ||
(priv->data_bitrate_const &&
nla_put(skb, IFLA_CAN_DATA_BITRATE_CONST,
sizeof(*priv->data_bitrate_const) *
priv->data_bitrate_const_cnt,
priv->data_bitrate_const))
)
return -EMSGSIZE;
return 0;
......@@ -1073,6 +1173,22 @@ static struct rtnl_link_ops can_link_ops __read_mostly = {
*/
int register_candev(struct net_device *dev)
{
struct can_priv *priv = netdev_priv(dev);
/* Ensure termination_const, termination_const_cnt and
* do_set_termination consistency. All must be either set or
* unset.
*/
if ((!priv->termination_const != !priv->termination_const_cnt) ||
(!priv->termination_const != !priv->do_set_termination))
return -EINVAL;
if (!priv->bitrate_const != !priv->bitrate_const_cnt)
return -EINVAL;
if (!priv->data_bitrate_const != !priv->data_bitrate_const_cnt)
return -EINVAL;
dev->rtnl_link_ops = &can_link_ops;
return register_netdev(dev);
}
......
......@@ -310,7 +310,7 @@ static int softingcs_probe(struct pcmcia_device *pcmcia)
pcmcia_failed:
pcmcia_disable_device(pcmcia);
pcmcia->priv = NULL;
return ret ?: -ENODEV;
return ret;
}
static const struct pcmcia_device_id softingcs_ids[] = {
......
......@@ -38,6 +38,13 @@ struct can_priv {
struct can_bittiming bittiming, data_bittiming;
const struct can_bittiming_const *bittiming_const,
*data_bittiming_const;
const u16 *termination_const;
unsigned int termination_const_cnt;
u16 termination;
const u32 *bitrate_const;
unsigned int bitrate_const_cnt;
const u32 *data_bitrate_const;
unsigned int data_bitrate_const_cnt;
struct can_clock clock;
enum can_state state;
......@@ -53,6 +60,7 @@ struct can_priv {
int (*do_set_bittiming)(struct net_device *dev);
int (*do_set_data_bittiming)(struct net_device *dev);
int (*do_set_mode)(struct net_device *dev, enum can_mode mode);
int (*do_set_termination)(struct net_device *dev, u16 term);
int (*do_get_state)(const struct net_device *dev,
enum can_state *state);
int (*do_get_berr_counter)(const struct net_device *dev,
......
......@@ -127,9 +127,16 @@ enum {
IFLA_CAN_BERR_COUNTER,
IFLA_CAN_DATA_BITTIMING,
IFLA_CAN_DATA_BITTIMING_CONST,
IFLA_CAN_TERMINATION,
IFLA_CAN_TERMINATION_CONST,
IFLA_CAN_BITRATE_CONST,
IFLA_CAN_DATA_BITRATE_CONST,
__IFLA_CAN_MAX
};
#define IFLA_CAN_MAX (__IFLA_CAN_MAX - 1)
/* u16 termination range: 1..65535 Ohms */
#define CAN_TERMINATION_DISABLED 0
#endif /* !_UAPI_CAN_NETLINK_H */
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