linux-can-next-for-6.3-20230206
-----BEGIN PGP SIGNATURE----- iQFHBAABCgAxFiEEDs2BvajyNKlf9TJQvlAcSiqKBOgFAmPg+r4THG1rbEBwZW5n dXRyb25peC5kZQAKCRC+UBxKKooE6A44B/0c8jjyLikVE2fEBKkvPk8iRlFKap48 140HNR+1TuVBBPCJTe2Gq3l8fDfFUgUVnFfVDjAQq6pMWufLkz9jVr5uGN7O94v+ tFCjip8NLRTa6ibgQlGrFXl31X5vqT+jV6V4l29wFgbwgOMRrod7wLDo+bHTtuuY 46Sf4GgIazYjxEeZBBsvjnAbraFq0twZFcEz9SyeOxqjR+9+71X4Y3x0kgQuz72N CrvRng0yFLqbHOBE60iaDqbjuNnwBGTH476pwX25Kj9gVyIH20T45h8tV4j6z2Sq A42cHKDlWZRWUiWQjGOHHT4igUf//Sfv8WDaFjqobO/DDY+nBA75EPAv =hWLT -----END PGP SIGNATURE----- Merge tag 'linux-can-next-for-6.3-20230206' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next Marc Kleine-Budde says: ==================== pull-request: can-next 2023-02-06 this is a pull request of 47 patches for net-next/master. The first two patch is by Oliver Hartkopp. One adds missing error checking to the CAN_GW protocol, the other adds a missing CAN address family check to the CAN ISO TP protocol. Thomas Kopp contributes a performance optimization to the mcp251xfd driver. The next 11 patches are by Geert Uytterhoeven and add support for R-Car V4H systems to the rcar_canfd driver. Stephane Grosjean and Lukas Magel contribute 8 patches to the peak_usb driver, which add support for configurable CAN channel ID. The last 17 patches are by me and target the CAN bit timing configuration. The bit timing is cleaned up, error messages are improved and forwarded to user space via NL_SET_ERR_MSG_FMT() instead of netdev_err(), and the SJW handling is updated, including the definition of a new default value that will benefit CAN-FD controllers, by increasing their oscillator tolerance. * tag 'linux-can-next-for-6.3-20230206' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can-next: (47 commits) can: bittiming: can_validate_bitrate(): report error via netlink can: bittiming: can_calc_bittiming(): convert from netdev_err() to NL_SET_ERR_MSG_FMT() can: bittiming: can_calc_bittiming(): clean up SJW handling can: bittiming: can_sjw_set_default(): use Phase Seg2 / 2 as default for SJW can: bittiming: can_sjw_check(): check that SJW is not longer than either Phase Buffer Segment can: bittiming: can_sjw_check(): report error via netlink and harmonize error value can: bittiming: can_fixup_bittiming(): report error via netlink and harmonize error value can: bittiming: factor out can_sjw_set_default() and can_sjw_check() can: bittiming: can_changelink() pass extack down callstack can: netlink: can_changelink(): convert from netdev_err() to NL_SET_ERR_MSG_FMT() can: netlink: can_validate(): validate sample point for CAN and CAN-FD can: dev: register_candev(): bail out if both fixed bit rates and bit timing constants are provided can: dev: register_candev(): ensure that bittiming const are valid can: bittiming: can_get_bittiming(): use direct return and remove unneeded else can: bittiming: can_fixup_bittiming(): set effective tq can: bittiming: can_fixup_bittiming(): use CAN_SYNC_SEG instead of 1 can: bittiming(): replace open coded variants of can_bit_time() can: peak_usb: Reorder include directives alphabetically can: peak_usb: align CAN channel ID format in log with sysfs attribute can: peak_usb: export PCAN CAN channel ID as sysfs device attribute ... ==================== Link: https://lore.kernel.org/r/20230206131620.2758724-1-mkl@pengutronix.de Signed-off-by: Paolo Abeni <pabeni@redhat.com>
This commit is contained in:
commit
61d731e653
|
@ -0,0 +1,19 @@
|
|||
|
||||
What: /sys/class/net/<iface>/peak_usb/can_channel_id
|
||||
Date: November 2022
|
||||
KernelVersion: 6.2
|
||||
Contact: Stephane Grosjean <s.grosjean@peak-system.com>
|
||||
Description:
|
||||
PEAK PCAN-USB devices support user-configurable CAN channel
|
||||
identifiers. Contrary to a USB serial number, these identifiers
|
||||
are writable and can be set per CAN interface. This means that
|
||||
if a USB device exports multiple CAN interfaces, each of them
|
||||
can be assigned a unique channel ID.
|
||||
This attribute provides read-only access to the currently
|
||||
configured value of the channel identifier. Depending on the
|
||||
device type, the identifier has a length of 8 or 32 bit. The
|
||||
value read from this attribute is always an 8 digit 32 bit
|
||||
hexadecimal value in big endian format. If the device only
|
||||
supports an 8 bit identifier, the upper 24 bit of the value are
|
||||
set to zero.
|
||||
|
|
@ -28,6 +28,12 @@ properties:
|
|||
- renesas,r8a77995-canfd # R-Car D3
|
||||
- const: renesas,rcar-gen3-canfd # R-Car Gen3 and RZ/G2
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,r8a779a0-canfd # R-Car V3U
|
||||
- renesas,r8a779g0-canfd # R-Car V4H
|
||||
- const: renesas,rcar-gen4-canfd # R-Car Gen4
|
||||
|
||||
- items:
|
||||
- enum:
|
||||
- renesas,r9a07g043-canfd # RZ/G2UL and RZ/Five
|
||||
|
@ -35,8 +41,6 @@ properties:
|
|||
- renesas,r9a07g054-canfd # RZ/V2L
|
||||
- const: renesas,rzg2l-canfd # RZ/G2L family
|
||||
|
||||
- const: renesas,r8a779a0-canfd # R-Car V3U
|
||||
|
||||
reg:
|
||||
maxItems: 1
|
||||
|
||||
|
@ -60,7 +64,7 @@ properties:
|
|||
$ref: /schemas/types.yaml#/definitions/flag
|
||||
description:
|
||||
The controller can operate in either CAN FD only mode (default) or
|
||||
Classical CAN only mode. The mode is global to both the channels.
|
||||
Classical CAN only mode. The mode is global to all channels.
|
||||
Specify this property to put the controller in Classical CAN only mode.
|
||||
|
||||
assigned-clocks:
|
||||
|
@ -80,6 +84,10 @@ patternProperties:
|
|||
The controller supports multiple channels and each is represented as a
|
||||
child node. Each channel can be enabled/disabled individually.
|
||||
|
||||
properties:
|
||||
phys:
|
||||
maxItems: 1
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
required:
|
||||
|
@ -159,7 +167,7 @@ allOf:
|
|||
properties:
|
||||
compatible:
|
||||
contains:
|
||||
const: renesas,r8a779a0-canfd
|
||||
const: renesas,rcar-gen4-canfd
|
||||
then:
|
||||
patternProperties:
|
||||
"^channel[2-7]$": false
|
||||
|
|
|
@ -6,25 +6,81 @@
|
|||
|
||||
#include <linux/can/dev.h>
|
||||
|
||||
void can_sjw_set_default(struct can_bittiming *bt)
|
||||
{
|
||||
if (bt->sjw)
|
||||
return;
|
||||
|
||||
/* If user space provides no sjw, use sane default of phase_seg2 / 2 */
|
||||
bt->sjw = max(1U, min(bt->phase_seg1, bt->phase_seg2 / 2));
|
||||
}
|
||||
|
||||
int can_sjw_check(const struct net_device *dev, const struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc, struct netlink_ext_ack *extack)
|
||||
{
|
||||
if (bt->sjw > btc->sjw_max) {
|
||||
NL_SET_ERR_MSG_FMT(extack, "sjw: %u greater than max sjw: %u",
|
||||
bt->sjw, btc->sjw_max);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (bt->sjw > bt->phase_seg1) {
|
||||
NL_SET_ERR_MSG_FMT(extack,
|
||||
"sjw: %u greater than phase-seg1: %u",
|
||||
bt->sjw, bt->phase_seg1);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (bt->sjw > bt->phase_seg2) {
|
||||
NL_SET_ERR_MSG_FMT(extack,
|
||||
"sjw: %u greater than phase-seg2: %u",
|
||||
bt->sjw, bt->phase_seg2);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Checks the validity of the specified bit-timing parameters prop_seg,
|
||||
* phase_seg1, phase_seg2 and sjw and tries to determine the bitrate
|
||||
* prescaler value brp. You can find more information in the header
|
||||
* file linux/can/netlink.h.
|
||||
*/
|
||||
static int can_fixup_bittiming(const struct net_device *dev, struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc)
|
||||
const struct can_bittiming_const *btc,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
const unsigned int tseg1 = bt->prop_seg + bt->phase_seg1;
|
||||
const struct can_priv *priv = netdev_priv(dev);
|
||||
unsigned int tseg1, alltseg;
|
||||
u64 brp64;
|
||||
int err;
|
||||
|
||||
tseg1 = bt->prop_seg + bt->phase_seg1;
|
||||
if (!bt->sjw)
|
||||
bt->sjw = 1;
|
||||
if (bt->sjw > btc->sjw_max ||
|
||||
tseg1 < btc->tseg1_min || tseg1 > btc->tseg1_max ||
|
||||
bt->phase_seg2 < btc->tseg2_min || bt->phase_seg2 > btc->tseg2_max)
|
||||
return -ERANGE;
|
||||
if (tseg1 < btc->tseg1_min) {
|
||||
NL_SET_ERR_MSG_FMT(extack, "prop-seg + phase-seg1: %u less than tseg1-min: %u",
|
||||
tseg1, btc->tseg1_min);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (tseg1 > btc->tseg1_max) {
|
||||
NL_SET_ERR_MSG_FMT(extack, "prop-seg + phase-seg1: %u greater than tseg1-max: %u",
|
||||
tseg1, btc->tseg1_max);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (bt->phase_seg2 < btc->tseg2_min) {
|
||||
NL_SET_ERR_MSG_FMT(extack, "phase-seg2: %u less than tseg2-min: %u",
|
||||
bt->phase_seg2, btc->tseg2_min);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (bt->phase_seg2 > btc->tseg2_max) {
|
||||
NL_SET_ERR_MSG_FMT(extack, "phase-seg2: %u greater than tseg2-max: %u",
|
||||
bt->phase_seg2, btc->tseg2_max);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
can_sjw_set_default(bt);
|
||||
|
||||
err = can_sjw_check(dev, bt, btc, extack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
brp64 = (u64)priv->clock.freq * (u64)bt->tq;
|
||||
if (btc->brp_inc > 1)
|
||||
|
@ -35,12 +91,21 @@ static int can_fixup_bittiming(const struct net_device *dev, struct can_bittimin
|
|||
brp64 *= btc->brp_inc;
|
||||
bt->brp = (u32)brp64;
|
||||
|
||||
if (bt->brp < btc->brp_min || bt->brp > btc->brp_max)
|
||||
if (bt->brp < btc->brp_min) {
|
||||
NL_SET_ERR_MSG_FMT(extack, "resulting brp: %u less than brp-min: %u",
|
||||
bt->brp, btc->brp_min);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (bt->brp > btc->brp_max) {
|
||||
NL_SET_ERR_MSG_FMT(extack, "resulting brp: %u greater than brp-max: %u",
|
||||
bt->brp, btc->brp_max);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
alltseg = bt->prop_seg + bt->phase_seg1 + bt->phase_seg2 + 1;
|
||||
bt->bitrate = priv->clock.freq / (bt->brp * alltseg);
|
||||
bt->sample_point = ((tseg1 + 1) * 1000) / alltseg;
|
||||
bt->bitrate = priv->clock.freq / (bt->brp * can_bit_time(bt));
|
||||
bt->sample_point = ((CAN_SYNC_SEG + tseg1) * 1000) / can_bit_time(bt);
|
||||
bt->tq = DIV_U64_ROUND_CLOSEST(mul_u32_u32(bt->brp, NSEC_PER_SEC),
|
||||
priv->clock.freq);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -49,7 +114,8 @@ static int can_fixup_bittiming(const struct net_device *dev, struct can_bittimin
|
|||
static int
|
||||
can_validate_bitrate(const struct net_device *dev, const struct can_bittiming *bt,
|
||||
const u32 *bitrate_const,
|
||||
const unsigned int bitrate_const_cnt)
|
||||
const unsigned int bitrate_const_cnt,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
|
@ -58,30 +124,30 @@ can_validate_bitrate(const struct net_device *dev, const struct can_bittiming *b
|
|||
return 0;
|
||||
}
|
||||
|
||||
NL_SET_ERR_MSG_FMT(extack, "bitrate %u bps not supported",
|
||||
bt->brp);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int can_get_bittiming(const struct net_device *dev, struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc,
|
||||
const u32 *bitrate_const,
|
||||
const unsigned int bitrate_const_cnt)
|
||||
const unsigned int bitrate_const_cnt,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
int err;
|
||||
|
||||
/* 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 && btc)
|
||||
err = can_calc_bittiming(dev, bt, btc);
|
||||
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;
|
||||
return can_calc_bittiming(dev, bt, btc, extack);
|
||||
if (bt->tq && !bt->bitrate && btc)
|
||||
return can_fixup_bittiming(dev, bt, btc, extack);
|
||||
if (!bt->tq && bt->bitrate && bitrate_const)
|
||||
return can_validate_bitrate(dev, bt, bitrate_const,
|
||||
bitrate_const_cnt, extack);
|
||||
|
||||
return err;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
|
|
@ -63,7 +63,7 @@ can_update_sample_point(const struct can_bittiming_const *btc,
|
|||
}
|
||||
|
||||
int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc)
|
||||
const struct can_bittiming_const *btc, struct netlink_ext_ack *extack)
|
||||
{
|
||||
struct can_priv *priv = netdev_priv(dev);
|
||||
unsigned int bitrate; /* current bitrate */
|
||||
|
@ -76,6 +76,7 @@ int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt,
|
|||
unsigned int best_brp = 0; /* current best value for brp */
|
||||
unsigned int brp, tsegall, tseg, tseg1 = 0, tseg2 = 0;
|
||||
u64 v64;
|
||||
int err;
|
||||
|
||||
/* Use CiA recommended sample points */
|
||||
if (bt->sample_point) {
|
||||
|
@ -133,13 +134,14 @@ int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt,
|
|||
do_div(v64, bt->bitrate);
|
||||
bitrate_error = (u32)v64;
|
||||
if (bitrate_error > CAN_CALC_MAX_ERROR) {
|
||||
netdev_err(dev,
|
||||
"bitrate error %d.%d%% too high\n",
|
||||
bitrate_error / 10, bitrate_error % 10);
|
||||
return -EDOM;
|
||||
NL_SET_ERR_MSG_FMT(extack,
|
||||
"bitrate error: %u.%u%% too high",
|
||||
bitrate_error / 10, bitrate_error % 10);
|
||||
return -EINVAL;
|
||||
}
|
||||
netdev_warn(dev, "bitrate error %d.%d%%\n",
|
||||
bitrate_error / 10, bitrate_error % 10);
|
||||
NL_SET_ERR_MSG_FMT(extack,
|
||||
"bitrate error: %u.%u%%",
|
||||
bitrate_error / 10, bitrate_error % 10);
|
||||
}
|
||||
|
||||
/* real sample point */
|
||||
|
@ -154,23 +156,17 @@ int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt,
|
|||
bt->phase_seg1 = tseg1 - bt->prop_seg;
|
||||
bt->phase_seg2 = tseg2;
|
||||
|
||||
/* check for sjw user settings */
|
||||
if (!bt->sjw || !btc->sjw_max) {
|
||||
bt->sjw = 1;
|
||||
} else {
|
||||
/* bt->sjw is at least 1 -> sanitize upper bound to sjw_max */
|
||||
if (bt->sjw > btc->sjw_max)
|
||||
bt->sjw = btc->sjw_max;
|
||||
/* bt->sjw must not be higher than tseg2 */
|
||||
if (tseg2 < bt->sjw)
|
||||
bt->sjw = tseg2;
|
||||
}
|
||||
can_sjw_set_default(bt);
|
||||
|
||||
err = can_sjw_check(dev, bt, btc, extack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
bt->brp = best_brp;
|
||||
|
||||
/* real bitrate */
|
||||
bt->bitrate = priv->clock.freq /
|
||||
(bt->brp * (CAN_SYNC_SEG + tseg1 + tseg2));
|
||||
(bt->brp * can_bit_time(bt));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -498,6 +498,18 @@ static int can_get_termination(struct net_device *ndev)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
can_bittiming_const_valid(const struct can_bittiming_const *btc)
|
||||
{
|
||||
if (!btc)
|
||||
return true;
|
||||
|
||||
if (!btc->sjw_max)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Register the CAN network device */
|
||||
int register_candev(struct net_device *dev)
|
||||
{
|
||||
|
@ -518,6 +530,15 @@ int register_candev(struct net_device *dev)
|
|||
if (!priv->data_bitrate_const != !priv->data_bitrate_const_cnt)
|
||||
return -EINVAL;
|
||||
|
||||
/* We only support either fixed bit rates or bit timing const. */
|
||||
if ((priv->bitrate_const || priv->data_bitrate_const) &&
|
||||
(priv->bittiming_const || priv->data_bittiming_const))
|
||||
return -EINVAL;
|
||||
|
||||
if (!can_bittiming_const_valid(priv->bittiming_const) ||
|
||||
!can_bittiming_const_valid(priv->data_bittiming_const))
|
||||
return -EINVAL;
|
||||
|
||||
if (!priv->termination_const) {
|
||||
err = can_get_termination(dev);
|
||||
if (err)
|
||||
|
|
|
@ -36,10 +36,24 @@ static const struct nla_policy can_tdc_policy[IFLA_CAN_TDC_MAX + 1] = {
|
|||
[IFLA_CAN_TDC_TDCF] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
static int can_validate_bittiming(const struct can_bittiming *bt,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
/* sample point is in one-tenth of a percent */
|
||||
if (bt->sample_point >= 1000) {
|
||||
NL_SET_ERR_MSG(extack, "sample point must be between 0 and 100%");
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int can_validate(struct nlattr *tb[], struct nlattr *data[],
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
bool is_can_fd = false;
|
||||
int err;
|
||||
|
||||
/* Make sure that valid CAN FD configurations always consist of
|
||||
* - nominal/arbitration bittiming
|
||||
|
@ -51,6 +65,15 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[],
|
|||
if (!data)
|
||||
return 0;
|
||||
|
||||
if (data[IFLA_CAN_BITTIMING]) {
|
||||
struct can_bittiming bt;
|
||||
|
||||
memcpy(&bt, nla_data(data[IFLA_CAN_BITTIMING]), sizeof(bt));
|
||||
err = can_validate_bittiming(&bt, extack);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
if (data[IFLA_CAN_CTRLMODE]) {
|
||||
struct can_ctrlmode *cm = nla_data(data[IFLA_CAN_CTRLMODE]);
|
||||
u32 tdc_flags = cm->flags & CAN_CTRLMODE_TDC_MASK;
|
||||
|
@ -71,7 +94,6 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[],
|
|||
*/
|
||||
if (data[IFLA_CAN_TDC]) {
|
||||
struct nlattr *tb_tdc[IFLA_CAN_TDC_MAX + 1];
|
||||
int err;
|
||||
|
||||
err = nla_parse_nested(tb_tdc, IFLA_CAN_TDC_MAX,
|
||||
data[IFLA_CAN_TDC],
|
||||
|
@ -102,6 +124,15 @@ static int can_validate(struct nlattr *tb[], struct nlattr *data[],
|
|||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
if (data[IFLA_CAN_DATA_BITTIMING]) {
|
||||
struct can_bittiming bt;
|
||||
|
||||
memcpy(&bt, nla_data(data[IFLA_CAN_DATA_BITTIMING]), sizeof(bt));
|
||||
err = can_validate_bittiming(&bt, extack);
|
||||
if (err)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -184,13 +215,15 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
|
|||
err = can_get_bittiming(dev, &bt,
|
||||
priv->bittiming_const,
|
||||
priv->bitrate_const,
|
||||
priv->bitrate_const_cnt);
|
||||
priv->bitrate_const_cnt,
|
||||
extack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (priv->bitrate_max && bt.bitrate > priv->bitrate_max) {
|
||||
netdev_err(dev, "arbitration bitrate surpasses transceiver capabilities of %d bps\n",
|
||||
priv->bitrate_max);
|
||||
NL_SET_ERR_MSG_FMT(extack,
|
||||
"arbitration bitrate %u bps surpasses transceiver capabilities of %u bps",
|
||||
bt.bitrate, priv->bitrate_max);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -288,13 +321,15 @@ static int can_changelink(struct net_device *dev, struct nlattr *tb[],
|
|||
err = can_get_bittiming(dev, &dbt,
|
||||
priv->data_bittiming_const,
|
||||
priv->data_bitrate_const,
|
||||
priv->data_bitrate_const_cnt);
|
||||
priv->data_bitrate_const_cnt,
|
||||
extack);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
if (priv->bitrate_max && dbt.bitrate > priv->bitrate_max) {
|
||||
netdev_err(dev, "canfd data bitrate surpasses transceiver capabilities of %d bps\n",
|
||||
priv->bitrate_max);
|
||||
NL_SET_ERR_MSG_FMT(extack,
|
||||
"CANFD data bitrate %u bps surpasses transceiver capabilities of %u bps",
|
||||
dbt.bitrate, priv->bitrate_max);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
|
|
@ -21,23 +21,23 @@
|
|||
* wherever it is modified to a readable name.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/can/dev.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/can/dev.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/iopoll.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/reset.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#define RCANFD_DRV_NAME "rcar_canfd"
|
||||
|
||||
|
@ -82,8 +82,8 @@
|
|||
#define RCANFD_GERFL_DEF BIT(0)
|
||||
|
||||
#define RCANFD_GERFL_ERR(gpriv, x) \
|
||||
((x) & (reg_v3u(gpriv, RCANFD_GERFL_EEF0_7, \
|
||||
RCANFD_GERFL_EEF(0) | RCANFD_GERFL_EEF(1)) | \
|
||||
((x) & (reg_gen4(gpriv, RCANFD_GERFL_EEF0_7, \
|
||||
RCANFD_GERFL_EEF(0) | RCANFD_GERFL_EEF(1)) | \
|
||||
RCANFD_GERFL_MES | \
|
||||
((gpriv)->fdmode ? RCANFD_GERFL_CMPOF : 0)))
|
||||
|
||||
|
@ -91,16 +91,16 @@
|
|||
|
||||
/* RSCFDnCFDGAFLCFG0 / RSCFDnGAFLCFG0 */
|
||||
#define RCANFD_GAFLCFG_SETRNC(gpriv, n, x) \
|
||||
(((x) & reg_v3u(gpriv, 0x1ff, 0xff)) << \
|
||||
(reg_v3u(gpriv, 16, 24) - (n) * reg_v3u(gpriv, 16, 8)))
|
||||
(((x) & reg_gen4(gpriv, 0x1ff, 0xff)) << \
|
||||
(reg_gen4(gpriv, 16, 24) - ((n) & 1) * reg_gen4(gpriv, 16, 8)))
|
||||
|
||||
#define RCANFD_GAFLCFG_GETRNC(gpriv, n, x) \
|
||||
(((x) >> (reg_v3u(gpriv, 16, 24) - (n) * reg_v3u(gpriv, 16, 8))) & \
|
||||
reg_v3u(gpriv, 0x1ff, 0xff))
|
||||
(((x) >> (reg_gen4(gpriv, 16, 24) - ((n) & 1) * reg_gen4(gpriv, 16, 8))) & \
|
||||
reg_gen4(gpriv, 0x1ff, 0xff))
|
||||
|
||||
/* RSCFDnCFDGAFLECTR / RSCFDnGAFLECTR */
|
||||
#define RCANFD_GAFLECTR_AFLDAE BIT(8)
|
||||
#define RCANFD_GAFLECTR_AFLPN(gpriv, x) ((x) & reg_v3u(gpriv, 0x7f, 0x1f))
|
||||
#define RCANFD_GAFLECTR_AFLPN(gpriv, x) ((x) & reg_gen4(gpriv, 0x7f, 0x1f))
|
||||
|
||||
/* RSCFDnCFDGAFLIDj / RSCFDnGAFLIDj */
|
||||
#define RCANFD_GAFLID_GAFLLB BIT(29)
|
||||
|
@ -118,13 +118,13 @@
|
|||
|
||||
/* RSCFDnCFDCmNCFG - CAN FD only */
|
||||
#define RCANFD_NCFG_NTSEG2(gpriv, x) \
|
||||
(((x) & reg_v3u(gpriv, 0x7f, 0x1f)) << reg_v3u(gpriv, 25, 24))
|
||||
(((x) & reg_gen4(gpriv, 0x7f, 0x1f)) << reg_gen4(gpriv, 25, 24))
|
||||
|
||||
#define RCANFD_NCFG_NTSEG1(gpriv, x) \
|
||||
(((x) & reg_v3u(gpriv, 0xff, 0x7f)) << reg_v3u(gpriv, 17, 16))
|
||||
(((x) & reg_gen4(gpriv, 0xff, 0x7f)) << reg_gen4(gpriv, 17, 16))
|
||||
|
||||
#define RCANFD_NCFG_NSJW(gpriv, x) \
|
||||
(((x) & reg_v3u(gpriv, 0x7f, 0x1f)) << reg_v3u(gpriv, 10, 11))
|
||||
(((x) & reg_gen4(gpriv, 0x7f, 0x1f)) << reg_gen4(gpriv, 10, 11))
|
||||
|
||||
#define RCANFD_NCFG_NBRP(x) (((x) & 0x3ff) << 0)
|
||||
|
||||
|
@ -186,19 +186,19 @@
|
|||
#define RCANFD_CERFL_ERR(x) ((x) & (0x7fff)) /* above bits 14:0 */
|
||||
|
||||
/* RSCFDnCFDCmDCFG */
|
||||
#define RCANFD_DCFG_DSJW(x) (((x) & 0x7) << 24)
|
||||
#define RCANFD_DCFG_DSJW(gpriv, x) (((x) & reg_gen4(gpriv, 0xf, 0x7)) << 24)
|
||||
|
||||
#define RCANFD_DCFG_DTSEG2(gpriv, x) \
|
||||
(((x) & reg_v3u(gpriv, 0x0f, 0x7)) << reg_v3u(gpriv, 16, 20))
|
||||
(((x) & reg_gen4(gpriv, 0x0f, 0x7)) << reg_gen4(gpriv, 16, 20))
|
||||
|
||||
#define RCANFD_DCFG_DTSEG1(gpriv, x) \
|
||||
(((x) & reg_v3u(gpriv, 0x1f, 0xf)) << reg_v3u(gpriv, 8, 16))
|
||||
(((x) & reg_gen4(gpriv, 0x1f, 0xf)) << reg_gen4(gpriv, 8, 16))
|
||||
|
||||
#define RCANFD_DCFG_DBRP(x) (((x) & 0xff) << 0)
|
||||
|
||||
/* RSCFDnCFDCmFDCFG */
|
||||
#define RCANFD_FDCFG_CLOE BIT(30)
|
||||
#define RCANFD_FDCFG_FDOE BIT(28)
|
||||
#define RCANFD_GEN4_FDCFG_CLOE BIT(30)
|
||||
#define RCANFD_GEN4_FDCFG_FDOE BIT(28)
|
||||
#define RCANFD_FDCFG_TDCE BIT(9)
|
||||
#define RCANFD_FDCFG_TDCOC BIT(8)
|
||||
#define RCANFD_FDCFG_TDCO(x) (((x) & 0x7f) >> 16)
|
||||
|
@ -233,10 +233,11 @@
|
|||
/* Common FIFO bits */
|
||||
|
||||
/* RSCFDnCFDCFCCk */
|
||||
#define RCANFD_CFCC_CFTML(gpriv, x) (((x) & 0xf) << reg_v3u(gpriv, 16, 20))
|
||||
#define RCANFD_CFCC_CFM(gpriv, x) (((x) & 0x3) << reg_v3u(gpriv, 8, 16))
|
||||
#define RCANFD_CFCC_CFTML(gpriv, x) \
|
||||
(((x) & reg_gen4(gpriv, 0x1f, 0xf)) << reg_gen4(gpriv, 16, 20))
|
||||
#define RCANFD_CFCC_CFM(gpriv, x) (((x) & 0x3) << reg_gen4(gpriv, 8, 16))
|
||||
#define RCANFD_CFCC_CFIM BIT(12)
|
||||
#define RCANFD_CFCC_CFDC(gpriv, x) (((x) & 0x7) << reg_v3u(gpriv, 21, 8))
|
||||
#define RCANFD_CFCC_CFDC(gpriv, x) (((x) & 0x7) << reg_gen4(gpriv, 21, 8))
|
||||
#define RCANFD_CFCC_CFPLS(x) (((x) & 0x7) << 4)
|
||||
#define RCANFD_CFCC_CFTXIE BIT(2)
|
||||
#define RCANFD_CFCC_CFE BIT(0)
|
||||
|
@ -304,7 +305,7 @@
|
|||
#define RCANFD_RMND(y) (0x00a8 + (0x04 * (y)))
|
||||
|
||||
/* RSCFDnCFDRFCCx / RSCFDnRFCCx */
|
||||
#define RCANFD_RFCC(gpriv, x) (reg_v3u(gpriv, 0x00c0, 0x00b8) + (0x04 * (x)))
|
||||
#define RCANFD_RFCC(gpriv, x) (reg_gen4(gpriv, 0x00c0, 0x00b8) + (0x04 * (x)))
|
||||
/* RSCFDnCFDRFSTSx / RSCFDnRFSTSx */
|
||||
#define RCANFD_RFSTS(gpriv, x) (RCANFD_RFCC(gpriv, x) + 0x20)
|
||||
/* RSCFDnCFDRFPCTRx / RSCFDnRFPCTRx */
|
||||
|
@ -314,13 +315,13 @@
|
|||
|
||||
/* RSCFDnCFDCFCCx / RSCFDnCFCCx */
|
||||
#define RCANFD_CFCC(gpriv, ch, idx) \
|
||||
(reg_v3u(gpriv, 0x0120, 0x0118) + (0x0c * (ch)) + (0x04 * (idx)))
|
||||
(reg_gen4(gpriv, 0x0120, 0x0118) + (0x0c * (ch)) + (0x04 * (idx)))
|
||||
/* RSCFDnCFDCFSTSx / RSCFDnCFSTSx */
|
||||
#define RCANFD_CFSTS(gpriv, ch, idx) \
|
||||
(reg_v3u(gpriv, 0x01e0, 0x0178) + (0x0c * (ch)) + (0x04 * (idx)))
|
||||
(reg_gen4(gpriv, 0x01e0, 0x0178) + (0x0c * (ch)) + (0x04 * (idx)))
|
||||
/* RSCFDnCFDCFPCTRx / RSCFDnCFPCTRx */
|
||||
#define RCANFD_CFPCTR(gpriv, ch, idx) \
|
||||
(reg_v3u(gpriv, 0x0240, 0x01d8) + (0x0c * (ch)) + (0x04 * (idx)))
|
||||
(reg_gen4(gpriv, 0x0240, 0x01d8) + (0x0c * (ch)) + (0x04 * (idx)))
|
||||
|
||||
/* RSCFDnCFDFESTS / RSCFDnFESTS */
|
||||
#define RCANFD_FESTS (0x0238)
|
||||
|
@ -428,16 +429,15 @@
|
|||
/* RSCFDnRPGACCr */
|
||||
#define RCANFD_C_RPGACC(r) (0x1900 + (0x04 * (r)))
|
||||
|
||||
/* R-Car V3U Classical and CAN FD mode specific register map */
|
||||
#define RCANFD_V3U_CFDCFG (0x1314)
|
||||
#define RCANFD_V3U_DCFG(m) (0x1400 + (0x20 * (m)))
|
||||
/* R-Car Gen4 Classical and CAN FD mode specific register map */
|
||||
#define RCANFD_GEN4_FDCFG(m) (0x1404 + (0x20 * (m)))
|
||||
|
||||
#define RCANFD_V3U_GAFL_OFFSET (0x1800)
|
||||
#define RCANFD_GEN4_GAFL_OFFSET (0x1800)
|
||||
|
||||
/* CAN FD mode specific register map */
|
||||
|
||||
/* RSCFDnCFDCmXXX -> RCANFD_F_XXX(m) */
|
||||
#define RCANFD_F_DCFG(m) (0x0500 + (0x20 * (m)))
|
||||
#define RCANFD_F_DCFG(gpriv, m) (reg_gen4(gpriv, 0x1400, 0x0500) + (0x20 * (m)))
|
||||
#define RCANFD_F_CFDCFG(m) (0x0504 + (0x20 * (m)))
|
||||
#define RCANFD_F_CFDCTR(m) (0x0508 + (0x20 * (m)))
|
||||
#define RCANFD_F_CFDSTS(m) (0x050c + (0x20 * (m)))
|
||||
|
@ -453,7 +453,7 @@
|
|||
#define RCANFD_F_RMDF(q, b) (0x200c + (0x04 * (b)) + (0x20 * (q)))
|
||||
|
||||
/* RSCFDnCFDRFXXx -> RCANFD_F_RFXX(x) */
|
||||
#define RCANFD_F_RFOFFSET(gpriv) reg_v3u(gpriv, 0x6000, 0x3000)
|
||||
#define RCANFD_F_RFOFFSET(gpriv) reg_gen4(gpriv, 0x6000, 0x3000)
|
||||
#define RCANFD_F_RFID(gpriv, x) (RCANFD_F_RFOFFSET(gpriv) + (0x80 * (x)))
|
||||
#define RCANFD_F_RFPTR(gpriv, x) (RCANFD_F_RFOFFSET(gpriv) + 0x04 + (0x80 * (x)))
|
||||
#define RCANFD_F_RFFDSTS(gpriv, x) (RCANFD_F_RFOFFSET(gpriv) + 0x08 + (0x80 * (x)))
|
||||
|
@ -461,7 +461,7 @@
|
|||
(RCANFD_F_RFOFFSET(gpriv) + 0x0c + (0x80 * (x)) + (0x04 * (df)))
|
||||
|
||||
/* RSCFDnCFDCFXXk -> RCANFD_F_CFXX(ch, k) */
|
||||
#define RCANFD_F_CFOFFSET(gpriv) reg_v3u(gpriv, 0x6400, 0x3400)
|
||||
#define RCANFD_F_CFOFFSET(gpriv) reg_gen4(gpriv, 0x6400, 0x3400)
|
||||
|
||||
#define RCANFD_F_CFID(gpriv, ch, idx) \
|
||||
(RCANFD_F_CFOFFSET(gpriv) + (0x180 * (ch)) + (0x80 * (idx)))
|
||||
|
@ -597,28 +597,28 @@ static const struct rcar_canfd_hw_info rcar_gen3_hw_info = {
|
|||
.shared_global_irqs = 1,
|
||||
};
|
||||
|
||||
static const struct rcar_canfd_hw_info rcar_gen4_hw_info = {
|
||||
.max_channels = 8,
|
||||
.postdiv = 2,
|
||||
.shared_global_irqs = 1,
|
||||
};
|
||||
|
||||
static const struct rcar_canfd_hw_info rzg2l_hw_info = {
|
||||
.max_channels = 2,
|
||||
.postdiv = 1,
|
||||
.multi_channel_irqs = 1,
|
||||
};
|
||||
|
||||
static const struct rcar_canfd_hw_info r8a779a0_hw_info = {
|
||||
.max_channels = 8,
|
||||
.postdiv = 2,
|
||||
.shared_global_irqs = 1,
|
||||
};
|
||||
|
||||
/* Helper functions */
|
||||
static inline bool is_v3u(struct rcar_canfd_global *gpriv)
|
||||
static inline bool is_gen4(struct rcar_canfd_global *gpriv)
|
||||
{
|
||||
return gpriv->info == &r8a779a0_hw_info;
|
||||
return gpriv->info == &rcar_gen4_hw_info;
|
||||
}
|
||||
|
||||
static inline u32 reg_v3u(struct rcar_canfd_global *gpriv,
|
||||
u32 v3u, u32 not_v3u)
|
||||
static inline u32 reg_gen4(struct rcar_canfd_global *gpriv,
|
||||
u32 gen4, u32 not_gen4)
|
||||
{
|
||||
return is_v3u(gpriv) ? v3u : not_v3u;
|
||||
return is_gen4(gpriv) ? gen4 : not_gen4;
|
||||
}
|
||||
|
||||
static inline void rcar_canfd_update(u32 mask, u32 val, u32 __iomem *reg)
|
||||
|
@ -688,13 +688,14 @@ static void rcar_canfd_tx_failure_cleanup(struct net_device *ndev)
|
|||
|
||||
static void rcar_canfd_set_mode(struct rcar_canfd_global *gpriv)
|
||||
{
|
||||
if (is_v3u(gpriv)) {
|
||||
if (gpriv->fdmode)
|
||||
rcar_canfd_set_bit(gpriv->base, RCANFD_V3U_CFDCFG,
|
||||
RCANFD_FDCFG_FDOE);
|
||||
else
|
||||
rcar_canfd_set_bit(gpriv->base, RCANFD_V3U_CFDCFG,
|
||||
RCANFD_FDCFG_CLOE);
|
||||
if (is_gen4(gpriv)) {
|
||||
u32 ch, val = gpriv->fdmode ? RCANFD_GEN4_FDCFG_FDOE
|
||||
: RCANFD_GEN4_FDCFG_CLOE;
|
||||
|
||||
for_each_set_bit(ch, &gpriv->channels_mask,
|
||||
gpriv->info->max_channels)
|
||||
rcar_canfd_set_bit(gpriv->base, RCANFD_GEN4_FDCFG(ch),
|
||||
val);
|
||||
} else {
|
||||
if (gpriv->fdmode)
|
||||
rcar_canfd_set_bit(gpriv->base, RCANFD_GRMCFG,
|
||||
|
@ -814,8 +815,8 @@ static void rcar_canfd_configure_afl_rules(struct rcar_canfd_global *gpriv,
|
|||
/* Write number of rules for channel */
|
||||
rcar_canfd_set_bit(gpriv->base, RCANFD_GAFLCFG(ch),
|
||||
RCANFD_GAFLCFG_SETRNC(gpriv, ch, num_rules));
|
||||
if (is_v3u(gpriv))
|
||||
offset = RCANFD_V3U_GAFL_OFFSET;
|
||||
if (is_gen4(gpriv))
|
||||
offset = RCANFD_GEN4_GAFL_OFFSET;
|
||||
else if (gpriv->fdmode)
|
||||
offset = RCANFD_F_GAFL_OFFSET;
|
||||
else
|
||||
|
@ -1343,17 +1344,14 @@ static void rcar_canfd_set_bittiming(struct net_device *dev)
|
|||
tseg2 = dbt->phase_seg2 - 1;
|
||||
|
||||
cfg = (RCANFD_DCFG_DTSEG1(gpriv, tseg1) | RCANFD_DCFG_DBRP(brp) |
|
||||
RCANFD_DCFG_DSJW(sjw) | RCANFD_DCFG_DTSEG2(gpriv, tseg2));
|
||||
RCANFD_DCFG_DSJW(gpriv, sjw) | RCANFD_DCFG_DTSEG2(gpriv, tseg2));
|
||||
|
||||
if (is_v3u(gpriv))
|
||||
rcar_canfd_write(priv->base, RCANFD_V3U_DCFG(ch), cfg);
|
||||
else
|
||||
rcar_canfd_write(priv->base, RCANFD_F_DCFG(ch), cfg);
|
||||
rcar_canfd_write(priv->base, RCANFD_F_DCFG(gpriv, ch), cfg);
|
||||
netdev_dbg(priv->ndev, "drate: brp %u, sjw %u, tseg1 %u, tseg2 %u\n",
|
||||
brp, sjw, tseg1, tseg2);
|
||||
} else {
|
||||
/* Classical CAN only mode */
|
||||
if (is_v3u(gpriv)) {
|
||||
if (is_gen4(gpriv)) {
|
||||
cfg = (RCANFD_NCFG_NTSEG1(gpriv, tseg1) |
|
||||
RCANFD_NCFG_NBRP(brp) |
|
||||
RCANFD_NCFG_NSJW(gpriv, sjw) |
|
||||
|
@ -1510,7 +1508,7 @@ static netdev_tx_t rcar_canfd_start_xmit(struct sk_buff *skb,
|
|||
|
||||
dlc = RCANFD_CFPTR_CFDLC(can_fd_len2dlc(cf->len));
|
||||
|
||||
if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) || is_v3u(gpriv)) {
|
||||
if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) || is_gen4(gpriv)) {
|
||||
rcar_canfd_write(priv->base,
|
||||
RCANFD_F_CFID(gpriv, ch, RCANFD_CFFIFO_IDX), id);
|
||||
rcar_canfd_write(priv->base,
|
||||
|
@ -1569,7 +1567,7 @@ static void rcar_canfd_rx_pkt(struct rcar_canfd_channel *priv)
|
|||
u32 ch = priv->channel;
|
||||
u32 ridx = ch + RCANFD_RFFIFO_IDX;
|
||||
|
||||
if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) || is_v3u(gpriv)) {
|
||||
if ((priv->can.ctrlmode & CAN_CTRLMODE_FD) || is_gen4(gpriv)) {
|
||||
id = rcar_canfd_read(priv->base, RCANFD_F_RFID(gpriv, ridx));
|
||||
dlc = rcar_canfd_read(priv->base, RCANFD_F_RFPTR(gpriv, ridx));
|
||||
|
||||
|
@ -1620,7 +1618,7 @@ static void rcar_canfd_rx_pkt(struct rcar_canfd_channel *priv)
|
|||
cf->len = can_cc_dlc2len(RCANFD_RFPTR_RFDLC(dlc));
|
||||
if (id & RCANFD_RFID_RFRTR)
|
||||
cf->can_id |= CAN_RTR_FLAG;
|
||||
else if (is_v3u(gpriv))
|
||||
else if (is_gen4(gpriv))
|
||||
rcar_canfd_get_data(priv, cf, RCANFD_F_RFDF(gpriv, ridx, 0));
|
||||
else
|
||||
rcar_canfd_get_data(priv, cf, RCANFD_C_RFDF(ridx, 0));
|
||||
|
@ -1717,13 +1715,14 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,
|
|||
{
|
||||
const struct rcar_canfd_hw_info *info = gpriv->info;
|
||||
struct platform_device *pdev = gpriv->pdev;
|
||||
struct device *dev = &pdev->dev;
|
||||
struct rcar_canfd_channel *priv;
|
||||
struct net_device *ndev;
|
||||
int err = -ENODEV;
|
||||
|
||||
ndev = alloc_candev(sizeof(*priv), RCANFD_FIFO_DEPTH);
|
||||
if (!ndev) {
|
||||
dev_err(&pdev->dev, "alloc_candev() failed\n");
|
||||
dev_err(dev, "alloc_candev() failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
priv = netdev_priv(ndev);
|
||||
|
@ -1736,7 +1735,7 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,
|
|||
priv->channel = ch;
|
||||
priv->gpriv = gpriv;
|
||||
priv->can.clock.freq = fcan_freq;
|
||||
dev_info(&pdev->dev, "can_clk rate is %u\n", priv->can.clock.freq);
|
||||
dev_info(dev, "can_clk rate is %u\n", priv->can.clock.freq);
|
||||
|
||||
if (info->multi_channel_irqs) {
|
||||
char *irq_name;
|
||||
|
@ -1755,31 +1754,31 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,
|
|||
goto fail;
|
||||
}
|
||||
|
||||
irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
|
||||
"canfd.ch%d_err", ch);
|
||||
irq_name = devm_kasprintf(dev, GFP_KERNEL, "canfd.ch%d_err",
|
||||
ch);
|
||||
if (!irq_name) {
|
||||
err = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
err = devm_request_irq(&pdev->dev, err_irq,
|
||||
err = devm_request_irq(dev, err_irq,
|
||||
rcar_canfd_channel_err_interrupt, 0,
|
||||
irq_name, priv);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "devm_request_irq CH Err(%d) failed, error %d\n",
|
||||
dev_err(dev, "devm_request_irq CH Err(%d) failed, error %d\n",
|
||||
err_irq, err);
|
||||
goto fail;
|
||||
}
|
||||
irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL,
|
||||
"canfd.ch%d_trx", ch);
|
||||
irq_name = devm_kasprintf(dev, GFP_KERNEL, "canfd.ch%d_trx",
|
||||
ch);
|
||||
if (!irq_name) {
|
||||
err = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
err = devm_request_irq(&pdev->dev, tx_irq,
|
||||
err = devm_request_irq(dev, tx_irq,
|
||||
rcar_canfd_channel_tx_interrupt, 0,
|
||||
irq_name, priv);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "devm_request_irq Tx (%d) failed, error %d\n",
|
||||
dev_err(dev, "devm_request_irq Tx (%d) failed, error %d\n",
|
||||
tx_irq, err);
|
||||
goto fail;
|
||||
}
|
||||
|
@ -1803,7 +1802,7 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,
|
|||
|
||||
priv->can.do_set_mode = rcar_canfd_do_set_mode;
|
||||
priv->can.do_get_berr_counter = rcar_canfd_get_berr_counter;
|
||||
SET_NETDEV_DEV(ndev, &pdev->dev);
|
||||
SET_NETDEV_DEV(ndev, dev);
|
||||
|
||||
netif_napi_add_weight(ndev, &priv->napi, rcar_canfd_rx_poll,
|
||||
RCANFD_NAPI_WEIGHT);
|
||||
|
@ -1811,11 +1810,10 @@ static int rcar_canfd_channel_probe(struct rcar_canfd_global *gpriv, u32 ch,
|
|||
gpriv->ch[priv->channel] = priv;
|
||||
err = register_candev(ndev);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev,
|
||||
"register_candev() failed, error %d\n", err);
|
||||
dev_err(dev, "register_candev() failed, error %d\n", err);
|
||||
goto fail_candev;
|
||||
}
|
||||
dev_info(&pdev->dev, "device registered (channel %u)\n", priv->channel);
|
||||
dev_info(dev, "device registered (channel %u)\n", priv->channel);
|
||||
return 0;
|
||||
|
||||
fail_candev:
|
||||
|
@ -1839,6 +1837,7 @@ static void rcar_canfd_channel_remove(struct rcar_canfd_global *gpriv, u32 ch)
|
|||
static int rcar_canfd_probe(struct platform_device *pdev)
|
||||
{
|
||||
const struct rcar_canfd_hw_info *info;
|
||||
struct device *dev = &pdev->dev;
|
||||
void __iomem *addr;
|
||||
u32 sts, ch, fcan_freq;
|
||||
struct rcar_canfd_global *gpriv;
|
||||
|
@ -1850,14 +1849,14 @@ static int rcar_canfd_probe(struct platform_device *pdev)
|
|||
char name[9] = "channelX";
|
||||
int i;
|
||||
|
||||
info = of_device_get_match_data(&pdev->dev);
|
||||
info = of_device_get_match_data(dev);
|
||||
|
||||
if (of_property_read_bool(pdev->dev.of_node, "renesas,no-can-fd"))
|
||||
if (of_property_read_bool(dev->of_node, "renesas,no-can-fd"))
|
||||
fdmode = false; /* Classical CAN only mode */
|
||||
|
||||
for (i = 0; i < info->max_channels; ++i) {
|
||||
name[7] = '0' + i;
|
||||
of_child = of_get_child_by_name(pdev->dev.of_node, name);
|
||||
of_child = of_get_child_by_name(dev->of_node, name);
|
||||
if (of_child && of_device_is_available(of_child))
|
||||
channels_mask |= BIT(i);
|
||||
of_node_put(of_child);
|
||||
|
@ -1890,7 +1889,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
/* Global controller context */
|
||||
gpriv = devm_kzalloc(&pdev->dev, sizeof(*gpriv), GFP_KERNEL);
|
||||
gpriv = devm_kzalloc(dev, sizeof(*gpriv), GFP_KERNEL);
|
||||
if (!gpriv)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -1899,32 +1898,30 @@ static int rcar_canfd_probe(struct platform_device *pdev)
|
|||
gpriv->fdmode = fdmode;
|
||||
gpriv->info = info;
|
||||
|
||||
gpriv->rstc1 = devm_reset_control_get_optional_exclusive(&pdev->dev,
|
||||
"rstp_n");
|
||||
gpriv->rstc1 = devm_reset_control_get_optional_exclusive(dev, "rstp_n");
|
||||
if (IS_ERR(gpriv->rstc1))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(gpriv->rstc1),
|
||||
return dev_err_probe(dev, PTR_ERR(gpriv->rstc1),
|
||||
"failed to get rstp_n\n");
|
||||
|
||||
gpriv->rstc2 = devm_reset_control_get_optional_exclusive(&pdev->dev,
|
||||
"rstc_n");
|
||||
gpriv->rstc2 = devm_reset_control_get_optional_exclusive(dev, "rstc_n");
|
||||
if (IS_ERR(gpriv->rstc2))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(gpriv->rstc2),
|
||||
return dev_err_probe(dev, PTR_ERR(gpriv->rstc2),
|
||||
"failed to get rstc_n\n");
|
||||
|
||||
/* Peripheral clock */
|
||||
gpriv->clkp = devm_clk_get(&pdev->dev, "fck");
|
||||
gpriv->clkp = devm_clk_get(dev, "fck");
|
||||
if (IS_ERR(gpriv->clkp))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(gpriv->clkp),
|
||||
return dev_err_probe(dev, PTR_ERR(gpriv->clkp),
|
||||
"cannot get peripheral clock\n");
|
||||
|
||||
/* fCAN clock: Pick External clock. If not available fallback to
|
||||
* CANFD clock
|
||||
*/
|
||||
gpriv->can_clk = devm_clk_get(&pdev->dev, "can_clk");
|
||||
gpriv->can_clk = devm_clk_get(dev, "can_clk");
|
||||
if (IS_ERR(gpriv->can_clk) || (clk_get_rate(gpriv->can_clk) == 0)) {
|
||||
gpriv->can_clk = devm_clk_get(&pdev->dev, "canfd");
|
||||
gpriv->can_clk = devm_clk_get(dev, "canfd");
|
||||
if (IS_ERR(gpriv->can_clk))
|
||||
return dev_err_probe(&pdev->dev, PTR_ERR(gpriv->can_clk),
|
||||
return dev_err_probe(dev, PTR_ERR(gpriv->can_clk),
|
||||
"cannot get canfd clock\n");
|
||||
|
||||
gpriv->fcan = RCANFD_CANFDCLK;
|
||||
|
@ -1947,39 +1944,38 @@ static int rcar_canfd_probe(struct platform_device *pdev)
|
|||
|
||||
/* Request IRQ that's common for both channels */
|
||||
if (info->shared_global_irqs) {
|
||||
err = devm_request_irq(&pdev->dev, ch_irq,
|
||||
err = devm_request_irq(dev, ch_irq,
|
||||
rcar_canfd_channel_interrupt, 0,
|
||||
"canfd.ch_int", gpriv);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "devm_request_irq(%d) failed, error %d\n",
|
||||
dev_err(dev, "devm_request_irq(%d) failed, error %d\n",
|
||||
ch_irq, err);
|
||||
goto fail_dev;
|
||||
}
|
||||
|
||||
err = devm_request_irq(&pdev->dev, g_irq,
|
||||
rcar_canfd_global_interrupt, 0,
|
||||
"canfd.g_int", gpriv);
|
||||
err = devm_request_irq(dev, g_irq, rcar_canfd_global_interrupt,
|
||||
0, "canfd.g_int", gpriv);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "devm_request_irq(%d) failed, error %d\n",
|
||||
dev_err(dev, "devm_request_irq(%d) failed, error %d\n",
|
||||
g_irq, err);
|
||||
goto fail_dev;
|
||||
}
|
||||
} else {
|
||||
err = devm_request_irq(&pdev->dev, g_recc_irq,
|
||||
err = devm_request_irq(dev, g_recc_irq,
|
||||
rcar_canfd_global_receive_fifo_interrupt, 0,
|
||||
"canfd.g_recc", gpriv);
|
||||
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "devm_request_irq(%d) failed, error %d\n",
|
||||
dev_err(dev, "devm_request_irq(%d) failed, error %d\n",
|
||||
g_recc_irq, err);
|
||||
goto fail_dev;
|
||||
}
|
||||
|
||||
err = devm_request_irq(&pdev->dev, g_err_irq,
|
||||
err = devm_request_irq(dev, g_err_irq,
|
||||
rcar_canfd_global_err_interrupt, 0,
|
||||
"canfd.g_err", gpriv);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "devm_request_irq(%d) failed, error %d\n",
|
||||
dev_err(dev, "devm_request_irq(%d) failed, error %d\n",
|
||||
g_err_irq, err);
|
||||
goto fail_dev;
|
||||
}
|
||||
|
@ -1997,14 +1993,14 @@ static int rcar_canfd_probe(struct platform_device *pdev)
|
|||
/* Enable peripheral clock for register access */
|
||||
err = clk_prepare_enable(gpriv->clkp);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev,
|
||||
"failed to enable peripheral clock, error %d\n", err);
|
||||
dev_err(dev, "failed to enable peripheral clock, error %d\n",
|
||||
err);
|
||||
goto fail_reset;
|
||||
}
|
||||
|
||||
err = rcar_canfd_reset_controller(gpriv);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "reset controller failed\n");
|
||||
dev_err(dev, "reset controller failed\n");
|
||||
goto fail_clk;
|
||||
}
|
||||
|
||||
|
@ -2034,7 +2030,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
|
|||
err = readl_poll_timeout((gpriv->base + RCANFD_GSTS), sts,
|
||||
!(sts & RCANFD_GSTS_GNOPM), 2, 500000);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "global operational mode failed\n");
|
||||
dev_err(dev, "global operational mode failed\n");
|
||||
goto fail_mode;
|
||||
}
|
||||
|
||||
|
@ -2045,7 +2041,7 @@ static int rcar_canfd_probe(struct platform_device *pdev)
|
|||
}
|
||||
|
||||
platform_set_drvdata(pdev, gpriv);
|
||||
dev_info(&pdev->dev, "global operational state (clk %d, fdmode %d)\n",
|
||||
dev_info(dev, "global operational state (clk %d, fdmode %d)\n",
|
||||
gpriv->fcan, gpriv->fdmode);
|
||||
return 0;
|
||||
|
||||
|
@ -2099,9 +2095,10 @@ static SIMPLE_DEV_PM_OPS(rcar_canfd_pm_ops, rcar_canfd_suspend,
|
|||
rcar_canfd_resume);
|
||||
|
||||
static const __maybe_unused struct of_device_id rcar_canfd_of_table[] = {
|
||||
{ .compatible = "renesas,r8a779a0-canfd", .data = &rcar_gen4_hw_info },
|
||||
{ .compatible = "renesas,rcar-gen3-canfd", .data = &rcar_gen3_hw_info },
|
||||
{ .compatible = "renesas,rcar-gen4-canfd", .data = &rcar_gen4_hw_info },
|
||||
{ .compatible = "renesas,rzg2l-canfd", .data = &rzg2l_hw_info },
|
||||
{ .compatible = "renesas,r8a779a0-canfd", .data = &r8a779a0_hw_info },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* Copyright (C) 2007 Wolfgang Grandegger <wg@grandegger.com>
|
||||
* Copyright (C) 2008 Markus Plessing <plessing@ems-wuensche.com>
|
||||
* Copyright (C) 2008 Sebastian Haas <haas@ems-wuensche.com>
|
||||
* Copyright (C) 2023 EMS Dr. Thomas Wuensche
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
@ -19,12 +20,14 @@
|
|||
|
||||
#define DRV_NAME "ems_pci"
|
||||
|
||||
MODULE_AUTHOR("Sebastian Haas <haas@ems-wuenche.com>");
|
||||
MODULE_AUTHOR("Sebastian Haas <support@ems-wuensche.com>");
|
||||
MODULE_AUTHOR("Gerhard Uttenthaler <uttenthaler@ems-wuensche.com>");
|
||||
MODULE_DESCRIPTION("Socket-CAN driver for EMS CPC-PCI/PCIe/104P CAN cards");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
#define EMS_PCI_V1_MAX_CHAN 2
|
||||
#define EMS_PCI_V2_MAX_CHAN 4
|
||||
#define EMS_PCI_V3_MAX_CHAN 4
|
||||
#define EMS_PCI_MAX_CHAN EMS_PCI_V2_MAX_CHAN
|
||||
|
||||
struct ems_pci_card {
|
||||
|
@ -40,8 +43,7 @@ struct ems_pci_card {
|
|||
|
||||
#define EMS_PCI_CAN_CLOCK (16000000 / 2)
|
||||
|
||||
/*
|
||||
* Register definitions and descriptions are from LinCAN 0.3.3.
|
||||
/* Register definitions and descriptions are from LinCAN 0.3.3.
|
||||
*
|
||||
* PSB4610 PITA-2 bridge control registers
|
||||
*/
|
||||
|
@ -52,8 +54,7 @@ struct ems_pci_card {
|
|||
#define PITA2_MISC 0x1c /* Miscellaneous Register */
|
||||
#define PITA2_MISC_CONFIG 0x04000000 /* Multiplexed parallel interface */
|
||||
|
||||
/*
|
||||
* Register definitions for the PLX 9030
|
||||
/* Register definitions for the PLX 9030
|
||||
*/
|
||||
#define PLX_ICSR 0x4c /* Interrupt Control/Status register */
|
||||
#define PLX_ICSR_LINTI1_ENA 0x0001 /* LINTi1 Enable */
|
||||
|
@ -62,8 +63,16 @@ struct ems_pci_card {
|
|||
#define PLX_ICSR_ENA_CLR (PLX_ICSR_LINTI1_ENA | PLX_ICSR_PCIINT_ENA | \
|
||||
PLX_ICSR_LINTI1_CLR)
|
||||
|
||||
/*
|
||||
* The board configuration is probably following:
|
||||
/* Register definitions for the ASIX99100
|
||||
*/
|
||||
#define ASIX_LINTSR 0x28 /* Interrupt Control/Status register */
|
||||
#define ASIX_LINTSR_INT0AC BIT(0) /* Writing 1 enables or clears interrupt */
|
||||
|
||||
#define ASIX_LIEMR 0x24 /* Local Interrupt Enable / Miscellaneous Register */
|
||||
#define ASIX_LIEMR_L0EINTEN BIT(16) /* Local INT0 input assertion enable */
|
||||
#define ASIX_LIEMR_LRST BIT(14) /* Local Reset assert */
|
||||
|
||||
/* The board configuration is probably following:
|
||||
* RX1 is connected to ground.
|
||||
* TX1 is not connected.
|
||||
* CLKO is not connected.
|
||||
|
@ -72,23 +81,40 @@ struct ems_pci_card {
|
|||
*/
|
||||
#define EMS_PCI_OCR (OCR_TX0_PUSHPULL | OCR_TX1_PUSHPULL)
|
||||
|
||||
/*
|
||||
* In the CDR register, you should set CBP to 1.
|
||||
/* In the CDR register, you should set CBP to 1.
|
||||
* You will probably also want to set the clock divider value to 7
|
||||
* (meaning direct oscillator output) because the second SJA1000 chip
|
||||
* is driven by the first one CLKOUT output.
|
||||
*/
|
||||
#define EMS_PCI_CDR (CDR_CBP | CDR_CLKOUT_MASK)
|
||||
|
||||
#define EMS_PCI_V1_BASE_BAR 1
|
||||
#define EMS_PCI_V1_CONF_SIZE 4096 /* size of PITA control area */
|
||||
#define EMS_PCI_V2_BASE_BAR 2
|
||||
#define EMS_PCI_V2_CONF_SIZE 128 /* size of PLX control area */
|
||||
#define EMS_PCI_CAN_BASE_OFFSET 0x400 /* offset where the controllers starts */
|
||||
#define EMS_PCI_CAN_CTRL_SIZE 0x200 /* memory size for each controller */
|
||||
#define EMS_PCI_V1_BASE_BAR 1
|
||||
#define EMS_PCI_V1_CONF_BAR 0
|
||||
#define EMS_PCI_V1_CONF_SIZE 4096 /* size of PITA control area */
|
||||
#define EMS_PCI_V1_CAN_BASE_OFFSET 0x400 /* offset where the controllers start */
|
||||
#define EMS_PCI_V1_CAN_CTRL_SIZE 0x200 /* memory size for each controller */
|
||||
|
||||
#define EMS_PCI_V2_BASE_BAR 2
|
||||
#define EMS_PCI_V2_CONF_BAR 0
|
||||
#define EMS_PCI_V2_CONF_SIZE 128 /* size of PLX control area */
|
||||
#define EMS_PCI_V2_CAN_BASE_OFFSET 0x400 /* offset where the controllers start */
|
||||
#define EMS_PCI_V2_CAN_CTRL_SIZE 0x200 /* memory size for each controller */
|
||||
|
||||
#define EMS_PCI_V3_BASE_BAR 0
|
||||
#define EMS_PCI_V3_CONF_BAR 5
|
||||
#define EMS_PCI_V3_CONF_SIZE 128 /* size of ASIX control area */
|
||||
#define EMS_PCI_V3_CAN_BASE_OFFSET 0x00 /* offset where the controllers starts */
|
||||
#define EMS_PCI_V3_CAN_CTRL_SIZE 0x100 /* memory size for each controller */
|
||||
|
||||
#define EMS_PCI_BASE_SIZE 4096 /* size of controller area */
|
||||
|
||||
#ifndef PCI_VENDOR_ID_ASIX
|
||||
#define PCI_VENDOR_ID_ASIX 0x125b
|
||||
#define PCI_DEVICE_ID_ASIX_9110 0x9110
|
||||
#define PCI_SUBVENDOR_ID_ASIX 0xa000
|
||||
#endif
|
||||
#define PCI_SUBDEVICE_ID_EMS 0x4010
|
||||
|
||||
static const struct pci_device_id ems_pci_tbl[] = {
|
||||
/* CPC-PCI v1 */
|
||||
{PCI_VENDOR_ID_SIEMENS, 0x2104, PCI_ANY_ID, PCI_ANY_ID,},
|
||||
|
@ -96,12 +122,13 @@ static const struct pci_device_id ems_pci_tbl[] = {
|
|||
{PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_PLX, 0x4000},
|
||||
/* CPC-104P v2 */
|
||||
{PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9030, PCI_VENDOR_ID_PLX, 0x4002},
|
||||
/* CPC-PCIe v3 */
|
||||
{PCI_VENDOR_ID_ASIX, PCI_DEVICE_ID_ASIX_9110, PCI_SUBVENDOR_ID_ASIX, PCI_SUBDEVICE_ID_EMS},
|
||||
{0,}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, ems_pci_tbl);
|
||||
|
||||
/*
|
||||
* Helper to read internal registers from card logic (not CAN)
|
||||
/* Helper to read internal registers from card logic (not CAN)
|
||||
*/
|
||||
static u8 ems_pci_v1_readb(struct ems_pci_card *card, unsigned int port)
|
||||
{
|
||||
|
@ -146,8 +173,25 @@ static void ems_pci_v2_post_irq(const struct sja1000_priv *priv)
|
|||
writel(PLX_ICSR_ENA_CLR, card->conf_addr + PLX_ICSR);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if a CAN controller is present at the specified location
|
||||
static u8 ems_pci_v3_read_reg(const struct sja1000_priv *priv, int port)
|
||||
{
|
||||
return readb(priv->reg_base + port);
|
||||
}
|
||||
|
||||
static void ems_pci_v3_write_reg(const struct sja1000_priv *priv,
|
||||
int port, u8 val)
|
||||
{
|
||||
writeb(val, priv->reg_base + port);
|
||||
}
|
||||
|
||||
static void ems_pci_v3_post_irq(const struct sja1000_priv *priv)
|
||||
{
|
||||
struct ems_pci_card *card = (struct ems_pci_card *)priv->priv;
|
||||
|
||||
writel(ASIX_LINTSR_INT0AC, card->conf_addr + ASIX_LINTSR);
|
||||
}
|
||||
|
||||
/* Check if a CAN controller is present at the specified location
|
||||
* by trying to set 'em into the PeliCAN mode
|
||||
*/
|
||||
static inline int ems_pci_check_chan(const struct sja1000_priv *priv)
|
||||
|
@ -185,10 +229,10 @@ static void ems_pci_del_card(struct pci_dev *pdev)
|
|||
free_sja1000dev(dev);
|
||||
}
|
||||
|
||||
if (card->base_addr != NULL)
|
||||
if (card->base_addr)
|
||||
pci_iounmap(card->pci_dev, card->base_addr);
|
||||
|
||||
if (card->conf_addr != NULL)
|
||||
if (card->conf_addr)
|
||||
pci_iounmap(card->pci_dev, card->conf_addr);
|
||||
|
||||
kfree(card);
|
||||
|
@ -202,8 +246,7 @@ static void ems_pci_card_reset(struct ems_pci_card *card)
|
|||
writeb(0, card->base_addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Probe PCI device for EMS CAN signature and register each available
|
||||
/* Probe PCI device for EMS CAN signature and register each available
|
||||
* CAN channel to SJA1000 Socket-CAN subsystem.
|
||||
*/
|
||||
static int ems_pci_add_card(struct pci_dev *pdev,
|
||||
|
@ -212,7 +255,7 @@ static int ems_pci_add_card(struct pci_dev *pdev,
|
|||
struct sja1000_priv *priv;
|
||||
struct net_device *dev;
|
||||
struct ems_pci_card *card;
|
||||
int max_chan, conf_size, base_bar;
|
||||
int max_chan, conf_size, base_bar, conf_bar;
|
||||
int err, i;
|
||||
|
||||
/* Enabling PCI device */
|
||||
|
@ -222,8 +265,8 @@ static int ems_pci_add_card(struct pci_dev *pdev,
|
|||
}
|
||||
|
||||
/* Allocating card structures to hold addresses, ... */
|
||||
card = kzalloc(sizeof(struct ems_pci_card), GFP_KERNEL);
|
||||
if (card == NULL) {
|
||||
card = kzalloc(sizeof(*card), GFP_KERNEL);
|
||||
if (!card) {
|
||||
pci_disable_device(pdev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
@ -234,27 +277,35 @@ static int ems_pci_add_card(struct pci_dev *pdev,
|
|||
|
||||
card->channels = 0;
|
||||
|
||||
if (pdev->vendor == PCI_VENDOR_ID_PLX) {
|
||||
if (pdev->vendor == PCI_VENDOR_ID_ASIX) {
|
||||
card->version = 3; /* CPC-PCI v3 */
|
||||
max_chan = EMS_PCI_V3_MAX_CHAN;
|
||||
base_bar = EMS_PCI_V3_BASE_BAR;
|
||||
conf_bar = EMS_PCI_V3_CONF_BAR;
|
||||
conf_size = EMS_PCI_V3_CONF_SIZE;
|
||||
} else if (pdev->vendor == PCI_VENDOR_ID_PLX) {
|
||||
card->version = 2; /* CPC-PCI v2 */
|
||||
max_chan = EMS_PCI_V2_MAX_CHAN;
|
||||
base_bar = EMS_PCI_V2_BASE_BAR;
|
||||
conf_bar = EMS_PCI_V2_CONF_BAR;
|
||||
conf_size = EMS_PCI_V2_CONF_SIZE;
|
||||
} else {
|
||||
card->version = 1; /* CPC-PCI v1 */
|
||||
max_chan = EMS_PCI_V1_MAX_CHAN;
|
||||
base_bar = EMS_PCI_V1_BASE_BAR;
|
||||
conf_bar = EMS_PCI_V1_CONF_BAR;
|
||||
conf_size = EMS_PCI_V1_CONF_SIZE;
|
||||
}
|
||||
|
||||
/* Remap configuration space and controller memory area */
|
||||
card->conf_addr = pci_iomap(pdev, 0, conf_size);
|
||||
if (card->conf_addr == NULL) {
|
||||
card->conf_addr = pci_iomap(pdev, conf_bar, conf_size);
|
||||
if (!card->conf_addr) {
|
||||
err = -ENOMEM;
|
||||
goto failure_cleanup;
|
||||
}
|
||||
|
||||
card->base_addr = pci_iomap(pdev, base_bar, EMS_PCI_BASE_SIZE);
|
||||
if (card->base_addr == NULL) {
|
||||
if (!card->base_addr) {
|
||||
err = -ENOMEM;
|
||||
goto failure_cleanup;
|
||||
}
|
||||
|
@ -276,12 +327,20 @@ static int ems_pci_add_card(struct pci_dev *pdev,
|
|||
}
|
||||
}
|
||||
|
||||
if (card->version == 3) {
|
||||
/* ASIX chip asserts local reset to CAN controllers
|
||||
* after bootup until it is deasserted
|
||||
*/
|
||||
writel(readl(card->conf_addr + ASIX_LIEMR) & ~ASIX_LIEMR_LRST,
|
||||
card->conf_addr + ASIX_LIEMR);
|
||||
}
|
||||
|
||||
ems_pci_card_reset(card);
|
||||
|
||||
/* Detect available channels */
|
||||
for (i = 0; i < max_chan; i++) {
|
||||
dev = alloc_sja1000dev(0);
|
||||
if (dev == NULL) {
|
||||
if (!dev) {
|
||||
err = -ENOMEM;
|
||||
goto failure_cleanup;
|
||||
}
|
||||
|
@ -292,16 +351,25 @@ static int ems_pci_add_card(struct pci_dev *pdev,
|
|||
priv->irq_flags = IRQF_SHARED;
|
||||
|
||||
dev->irq = pdev->irq;
|
||||
priv->reg_base = card->base_addr + EMS_PCI_CAN_BASE_OFFSET
|
||||
+ (i * EMS_PCI_CAN_CTRL_SIZE);
|
||||
|
||||
if (card->version == 1) {
|
||||
priv->read_reg = ems_pci_v1_read_reg;
|
||||
priv->write_reg = ems_pci_v1_write_reg;
|
||||
priv->post_irq = ems_pci_v1_post_irq;
|
||||
} else {
|
||||
priv->reg_base = card->base_addr + EMS_PCI_V1_CAN_BASE_OFFSET
|
||||
+ (i * EMS_PCI_V1_CAN_CTRL_SIZE);
|
||||
} else if (card->version == 2) {
|
||||
priv->read_reg = ems_pci_v2_read_reg;
|
||||
priv->write_reg = ems_pci_v2_write_reg;
|
||||
priv->post_irq = ems_pci_v2_post_irq;
|
||||
priv->reg_base = card->base_addr + EMS_PCI_V2_CAN_BASE_OFFSET
|
||||
+ (i * EMS_PCI_V2_CAN_CTRL_SIZE);
|
||||
} else {
|
||||
priv->read_reg = ems_pci_v3_read_reg;
|
||||
priv->write_reg = ems_pci_v3_write_reg;
|
||||
priv->post_irq = ems_pci_v3_post_irq;
|
||||
priv->reg_base = card->base_addr + EMS_PCI_V3_CAN_BASE_OFFSET
|
||||
+ (i * EMS_PCI_V3_CAN_CTRL_SIZE);
|
||||
}
|
||||
|
||||
/* Check if channel is present */
|
||||
|
@ -313,20 +381,28 @@ static int ems_pci_add_card(struct pci_dev *pdev,
|
|||
SET_NETDEV_DEV(dev, &pdev->dev);
|
||||
dev->dev_id = i;
|
||||
|
||||
if (card->version == 1)
|
||||
if (card->version == 1) {
|
||||
/* reset int flag of pita */
|
||||
writel(PITA2_ICR_INT0_EN | PITA2_ICR_INT0,
|
||||
card->conf_addr + PITA2_ICR);
|
||||
else
|
||||
} else if (card->version == 2) {
|
||||
/* enable IRQ in PLX 9030 */
|
||||
writel(PLX_ICSR_ENA_CLR,
|
||||
card->conf_addr + PLX_ICSR);
|
||||
} else {
|
||||
/* Enable IRQ in AX99100 */
|
||||
writel(ASIX_LINTSR_INT0AC, card->conf_addr + ASIX_LINTSR);
|
||||
/* Enable local INT0 input enable */
|
||||
writel(readl(card->conf_addr + ASIX_LIEMR) | ASIX_LIEMR_L0EINTEN,
|
||||
card->conf_addr + ASIX_LIEMR);
|
||||
}
|
||||
|
||||
/* Register SJA1000 device */
|
||||
err = register_sja1000dev(dev);
|
||||
if (err) {
|
||||
dev_err(&pdev->dev, "Registering device failed "
|
||||
"(err=%d)\n", err);
|
||||
dev_err(&pdev->dev,
|
||||
"Registering device failed: %pe\n",
|
||||
ERR_PTR(err));
|
||||
free_sja1000dev(dev);
|
||||
goto failure_cleanup;
|
||||
}
|
||||
|
@ -334,7 +410,7 @@ static int ems_pci_add_card(struct pci_dev *pdev,
|
|||
card->channels++;
|
||||
|
||||
dev_info(&pdev->dev, "Channel #%d at 0x%p, irq %d\n",
|
||||
i + 1, priv->reg_base, dev->irq);
|
||||
i + 1, priv->reg_base, dev->irq);
|
||||
} else {
|
||||
free_sja1000dev(dev);
|
||||
}
|
||||
|
|
|
@ -30,11 +30,23 @@ mcp251xfd_cmd_prepare_write_reg(const struct mcp251xfd_priv *priv,
|
|||
last_byte = mcp251xfd_last_byte_set(mask);
|
||||
len = last_byte - first_byte + 1;
|
||||
|
||||
data = mcp251xfd_spi_cmd_write(priv, write_reg_buf, reg + first_byte);
|
||||
data = mcp251xfd_spi_cmd_write(priv, write_reg_buf, reg + first_byte, len);
|
||||
val_le32 = cpu_to_le32(val >> BITS_PER_BYTE * first_byte);
|
||||
memcpy(data, &val_le32, len);
|
||||
|
||||
if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG) {
|
||||
if (!(priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG)) {
|
||||
len += sizeof(write_reg_buf->nocrc.cmd);
|
||||
} else if (len == 1) {
|
||||
u16 crc;
|
||||
|
||||
/* CRC */
|
||||
len += sizeof(write_reg_buf->safe.cmd);
|
||||
crc = mcp251xfd_crc16_compute(&write_reg_buf->safe, len);
|
||||
put_unaligned_be16(crc, (void *)write_reg_buf + len);
|
||||
|
||||
/* Total length */
|
||||
len += sizeof(write_reg_buf->safe.crc);
|
||||
} else {
|
||||
u16 crc;
|
||||
|
||||
mcp251xfd_spi_cmd_crc_set_len_in_reg(&write_reg_buf->crc.cmd,
|
||||
|
@ -46,8 +58,6 @@ mcp251xfd_cmd_prepare_write_reg(const struct mcp251xfd_priv *priv,
|
|||
|
||||
/* Total length */
|
||||
len += sizeof(write_reg_buf->crc.crc);
|
||||
} else {
|
||||
len += sizeof(write_reg_buf->nocrc.cmd);
|
||||
}
|
||||
|
||||
return len;
|
||||
|
|
|
@ -504,6 +504,11 @@ union mcp251xfd_write_reg_buf {
|
|||
u8 data[4];
|
||||
__be16 crc;
|
||||
} crc;
|
||||
struct __packed {
|
||||
struct mcp251xfd_buf_cmd cmd;
|
||||
u8 data[1];
|
||||
__be16 crc;
|
||||
} safe;
|
||||
} ____cacheline_aligned;
|
||||
|
||||
struct mcp251xfd_tx_obj {
|
||||
|
@ -758,6 +763,13 @@ mcp251xfd_spi_cmd_write_crc_set_addr(struct mcp251xfd_buf_cmd_crc *cmd,
|
|||
cmd->cmd = cpu_to_be16(MCP251XFD_SPI_INSTRUCTION_WRITE_CRC | addr);
|
||||
}
|
||||
|
||||
static inline void
|
||||
mcp251xfd_spi_cmd_write_safe_set_addr(struct mcp251xfd_buf_cmd *cmd,
|
||||
u16 addr)
|
||||
{
|
||||
cmd->cmd = cpu_to_be16(MCP251XFD_SPI_INSTRUCTION_WRITE_CRC_SAFE | addr);
|
||||
}
|
||||
|
||||
static inline void
|
||||
mcp251xfd_spi_cmd_write_crc(struct mcp251xfd_buf_cmd_crc *cmd,
|
||||
u16 addr, u16 len)
|
||||
|
@ -769,14 +781,20 @@ mcp251xfd_spi_cmd_write_crc(struct mcp251xfd_buf_cmd_crc *cmd,
|
|||
static inline u8 *
|
||||
mcp251xfd_spi_cmd_write(const struct mcp251xfd_priv *priv,
|
||||
union mcp251xfd_write_reg_buf *write_reg_buf,
|
||||
u16 addr)
|
||||
u16 addr, u8 len)
|
||||
{
|
||||
u8 *data;
|
||||
|
||||
if (priv->devtype_data.quirks & MCP251XFD_QUIRK_CRC_REG) {
|
||||
mcp251xfd_spi_cmd_write_crc_set_addr(&write_reg_buf->crc.cmd,
|
||||
addr);
|
||||
data = write_reg_buf->crc.data;
|
||||
if (len == 1) {
|
||||
mcp251xfd_spi_cmd_write_safe_set_addr(&write_reg_buf->safe.cmd,
|
||||
addr);
|
||||
data = write_reg_buf->safe.data;
|
||||
} else {
|
||||
mcp251xfd_spi_cmd_write_crc_set_addr(&write_reg_buf->crc.cmd,
|
||||
addr);
|
||||
data = write_reg_buf->crc.data;
|
||||
}
|
||||
} else {
|
||||
mcp251xfd_spi_cmd_write_nocrc(&write_reg_buf->nocrc.cmd,
|
||||
addr);
|
||||
|
|
|
@ -9,10 +9,11 @@
|
|||
* Many thanks to Klaus Hitschler <klaus.hitschler@gmx.de>
|
||||
*/
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ethtool.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/dev.h>
|
||||
|
@ -381,23 +382,42 @@ static int pcan_usb_get_serial(struct peak_usb_device *dev, u32 *serial_number)
|
|||
}
|
||||
|
||||
/*
|
||||
* read device id from device
|
||||
* read can channel id from device
|
||||
*/
|
||||
static int pcan_usb_get_device_id(struct peak_usb_device *dev, u32 *device_id)
|
||||
static int pcan_usb_get_can_channel_id(struct peak_usb_device *dev, u32 *can_ch_id)
|
||||
{
|
||||
u8 args[PCAN_USB_CMD_ARGS_LEN];
|
||||
int err;
|
||||
|
||||
err = pcan_usb_wait_rsp(dev, PCAN_USB_CMD_DEVID, PCAN_USB_GET, args);
|
||||
if (err)
|
||||
netdev_err(dev->netdev, "getting device id failure: %d\n", err);
|
||||
netdev_err(dev->netdev, "getting can channel id failure: %d\n", err);
|
||||
|
||||
else
|
||||
*device_id = args[0];
|
||||
*can_ch_id = args[0];
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* set a new CAN channel id in the flash memory of the device */
|
||||
static int pcan_usb_set_can_channel_id(struct peak_usb_device *dev, u32 can_ch_id)
|
||||
{
|
||||
u8 args[PCAN_USB_CMD_ARGS_LEN];
|
||||
|
||||
/* this kind of device supports 8-bit values only */
|
||||
if (can_ch_id > U8_MAX)
|
||||
return -EINVAL;
|
||||
|
||||
/* during the flash process the device disconnects during ~1.25 s.:
|
||||
* prohibit access when interface is UP
|
||||
*/
|
||||
if (dev->netdev->flags & IFF_UP)
|
||||
return -EBUSY;
|
||||
|
||||
args[0] = can_ch_id;
|
||||
return pcan_usb_send_cmd(dev, PCAN_USB_CMD_DEVID, PCAN_USB_SET, args);
|
||||
}
|
||||
|
||||
/*
|
||||
* update current time ref with received timestamp
|
||||
*/
|
||||
|
@ -963,9 +983,18 @@ static int pcan_usb_set_phys_id(struct net_device *netdev,
|
|||
return err;
|
||||
}
|
||||
|
||||
/* This device only handles 8-bit CAN channel id. */
|
||||
static int pcan_usb_get_eeprom_len(struct net_device *netdev)
|
||||
{
|
||||
return sizeof(u8);
|
||||
}
|
||||
|
||||
static const struct ethtool_ops pcan_usb_ethtool_ops = {
|
||||
.set_phys_id = pcan_usb_set_phys_id,
|
||||
.get_ts_info = pcan_get_ts_info,
|
||||
.get_eeprom_len = pcan_usb_get_eeprom_len,
|
||||
.get_eeprom = peak_usb_get_eeprom,
|
||||
.set_eeprom = peak_usb_set_eeprom,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1017,7 +1046,8 @@ const struct peak_usb_adapter pcan_usb = {
|
|||
.dev_init = pcan_usb_init,
|
||||
.dev_set_bus = pcan_usb_write_mode,
|
||||
.dev_set_bittiming = pcan_usb_set_bittiming,
|
||||
.dev_get_device_id = pcan_usb_get_device_id,
|
||||
.dev_get_can_channel_id = pcan_usb_get_can_channel_id,
|
||||
.dev_set_can_channel_id = pcan_usb_set_can_channel_id,
|
||||
.dev_decode_buf = pcan_usb_decode_buf,
|
||||
.dev_encode_msg = pcan_usb_encode_msg,
|
||||
.dev_start = pcan_usb_start,
|
||||
|
|
|
@ -8,13 +8,15 @@
|
|||
*
|
||||
* Many thanks to Klaus Hitschler <klaus.hitschler@gmx.de>
|
||||
*/
|
||||
#include <linux/device.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/signal.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/ethtool.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/dev.h>
|
||||
|
@ -53,6 +55,26 @@ static const struct usb_device_id peak_usb_table[] = {
|
|||
|
||||
MODULE_DEVICE_TABLE(usb, peak_usb_table);
|
||||
|
||||
static ssize_t can_channel_id_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct net_device *netdev = to_net_dev(dev);
|
||||
struct peak_usb_device *peak_dev = netdev_priv(netdev);
|
||||
|
||||
return sysfs_emit(buf, "%08X\n", peak_dev->can_channel_id);
|
||||
}
|
||||
static DEVICE_ATTR_RO(can_channel_id);
|
||||
|
||||
/* mutable to avoid cast in attribute_group */
|
||||
static struct attribute *peak_usb_sysfs_attrs[] = {
|
||||
&dev_attr_can_channel_id.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const struct attribute_group peak_usb_sysfs_group = {
|
||||
.name = "peak_usb",
|
||||
.attrs = peak_usb_sysfs_attrs,
|
||||
};
|
||||
|
||||
/*
|
||||
* dump memory
|
||||
*/
|
||||
|
@ -808,6 +830,86 @@ static const struct net_device_ops peak_usb_netdev_ops = {
|
|||
.ndo_change_mtu = can_change_mtu,
|
||||
};
|
||||
|
||||
/* CAN-USB devices generally handle 32-bit CAN channel IDs.
|
||||
* In case one doesn't, then it have to overload this function.
|
||||
*/
|
||||
int peak_usb_get_eeprom_len(struct net_device *netdev)
|
||||
{
|
||||
return sizeof(u32);
|
||||
}
|
||||
|
||||
/* Every CAN-USB device exports the dev_get_can_channel_id() operation. It is used
|
||||
* here to fill the data buffer with the user defined CAN channel ID.
|
||||
*/
|
||||
int peak_usb_get_eeprom(struct net_device *netdev,
|
||||
struct ethtool_eeprom *eeprom, u8 *data)
|
||||
{
|
||||
struct peak_usb_device *dev = netdev_priv(netdev);
|
||||
u32 ch_id;
|
||||
__le32 ch_id_le;
|
||||
int err;
|
||||
|
||||
err = dev->adapter->dev_get_can_channel_id(dev, &ch_id);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/* ethtool operates on individual bytes. The byte order of the CAN
|
||||
* channel id in memory depends on the kernel architecture. We
|
||||
* convert the CAN channel id back to the native byte order of the PEAK
|
||||
* device itself to ensure that the order is consistent for all
|
||||
* host architectures.
|
||||
*/
|
||||
ch_id_le = cpu_to_le32(ch_id);
|
||||
memcpy(data, (u8 *)&ch_id_le + eeprom->offset, eeprom->len);
|
||||
|
||||
/* update cached value */
|
||||
dev->can_channel_id = ch_id;
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Every CAN-USB device exports the dev_get_can_channel_id()/dev_set_can_channel_id()
|
||||
* operations. They are used here to set the new user defined CAN channel ID.
|
||||
*/
|
||||
int peak_usb_set_eeprom(struct net_device *netdev,
|
||||
struct ethtool_eeprom *eeprom, u8 *data)
|
||||
{
|
||||
struct peak_usb_device *dev = netdev_priv(netdev);
|
||||
u32 ch_id;
|
||||
__le32 ch_id_le;
|
||||
int err;
|
||||
|
||||
/* first, read the current user defined CAN channel ID */
|
||||
err = dev->adapter->dev_get_can_channel_id(dev, &ch_id);
|
||||
if (err) {
|
||||
netdev_err(netdev, "Failed to init CAN channel id (err %d)\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* do update the value with user given bytes.
|
||||
* ethtool operates on individual bytes. The byte order of the CAN
|
||||
* channel ID in memory depends on the kernel architecture. We
|
||||
* convert the CAN channel ID back to the native byte order of the PEAK
|
||||
* device itself to ensure that the order is consistent for all
|
||||
* host architectures.
|
||||
*/
|
||||
ch_id_le = cpu_to_le32(ch_id);
|
||||
memcpy((u8 *)&ch_id_le + eeprom->offset, data, eeprom->len);
|
||||
ch_id = le32_to_cpu(ch_id_le);
|
||||
|
||||
/* flash the new value now */
|
||||
err = dev->adapter->dev_set_can_channel_id(dev, ch_id);
|
||||
if (err) {
|
||||
netdev_err(netdev, "Failed to write new CAN channel id (err %d)\n",
|
||||
err);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* update cached value with the new one */
|
||||
dev->can_channel_id = ch_id;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pcan_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info)
|
||||
{
|
||||
info->so_timestamping =
|
||||
|
@ -881,6 +983,9 @@ static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter,
|
|||
/* add ethtool support */
|
||||
netdev->ethtool_ops = peak_usb_adapter->ethtool_ops;
|
||||
|
||||
/* register peak_usb sysfs files */
|
||||
netdev->sysfs_groups[0] = &peak_usb_sysfs_group;
|
||||
|
||||
init_usb_anchor(&dev->rx_submitted);
|
||||
|
||||
init_usb_anchor(&dev->tx_submitted);
|
||||
|
@ -921,12 +1026,11 @@ static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter,
|
|||
goto adap_dev_free;
|
||||
}
|
||||
|
||||
/* get device number early */
|
||||
if (dev->adapter->dev_get_device_id)
|
||||
dev->adapter->dev_get_device_id(dev, &dev->device_number);
|
||||
/* get CAN channel id early */
|
||||
dev->adapter->dev_get_can_channel_id(dev, &dev->can_channel_id);
|
||||
|
||||
netdev_info(netdev, "attached to %s channel %u (device %u)\n",
|
||||
peak_usb_adapter->name, ctrl_idx, dev->device_number);
|
||||
netdev_info(netdev, "attached to %s channel %u (device 0x%08X)\n",
|
||||
peak_usb_adapter->name, ctrl_idx, dev->can_channel_id);
|
||||
|
||||
return 0;
|
||||
|
||||
|
@ -964,7 +1068,7 @@ static void peak_usb_disconnect(struct usb_interface *intf)
|
|||
dev->state &= ~PCAN_USB_STATE_CONNECTED;
|
||||
strscpy(name, netdev->name, IFNAMSIZ);
|
||||
|
||||
unregister_netdev(netdev);
|
||||
unregister_candev(netdev);
|
||||
|
||||
kfree(dev->cmd_buf);
|
||||
dev->next_siblings = NULL;
|
||||
|
|
|
@ -60,7 +60,8 @@ struct peak_usb_adapter {
|
|||
int (*dev_set_data_bittiming)(struct peak_usb_device *dev,
|
||||
struct can_bittiming *bt);
|
||||
int (*dev_set_bus)(struct peak_usb_device *dev, u8 onoff);
|
||||
int (*dev_get_device_id)(struct peak_usb_device *dev, u32 *device_id);
|
||||
int (*dev_get_can_channel_id)(struct peak_usb_device *dev, u32 *can_ch_id);
|
||||
int (*dev_set_can_channel_id)(struct peak_usb_device *dev, u32 can_ch_id);
|
||||
int (*dev_decode_buf)(struct peak_usb_device *dev, struct urb *urb);
|
||||
int (*dev_encode_msg)(struct peak_usb_device *dev, struct sk_buff *skb,
|
||||
u8 *obuf, size_t *size);
|
||||
|
@ -122,7 +123,8 @@ struct peak_usb_device {
|
|||
u8 *cmd_buf;
|
||||
struct usb_anchor rx_submitted;
|
||||
|
||||
u32 device_number;
|
||||
/* equivalent to the device ID in the Windows API */
|
||||
u32 can_channel_id;
|
||||
u8 device_rev;
|
||||
|
||||
u8 ep_msg_in;
|
||||
|
@ -147,4 +149,10 @@ void peak_usb_async_complete(struct urb *urb);
|
|||
void peak_usb_restart_complete(struct peak_usb_device *dev);
|
||||
int pcan_get_ts_info(struct net_device *dev, struct ethtool_ts_info *info);
|
||||
|
||||
/* common 32-bit CAN channel ID ethtool management */
|
||||
int peak_usb_get_eeprom_len(struct net_device *netdev);
|
||||
int peak_usb_get_eeprom(struct net_device *netdev,
|
||||
struct ethtool_eeprom *eeprom, u8 *data);
|
||||
int peak_usb_set_eeprom(struct net_device *netdev,
|
||||
struct ethtool_eeprom *eeprom, u8 *data);
|
||||
#endif
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
*
|
||||
* Copyright (C) 2013-2014 Stephane Grosjean <s.grosjean@peak-system.com>
|
||||
*/
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ethtool.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/dev.h>
|
||||
|
@ -147,6 +147,15 @@ struct __packed pcan_ufd_ovr_msg {
|
|||
u8 unused[3];
|
||||
};
|
||||
|
||||
#define PCAN_UFD_CMD_DEVID_SET 0x81
|
||||
|
||||
struct __packed pcan_ufd_device_id {
|
||||
__le16 opcode_channel;
|
||||
|
||||
u16 unused;
|
||||
__le32 device_id;
|
||||
};
|
||||
|
||||
static inline int pufd_omsg_get_channel(struct pcan_ufd_ovr_msg *om)
|
||||
{
|
||||
return om->channel & 0xf;
|
||||
|
@ -234,6 +243,15 @@ static int pcan_usb_fd_send_cmd(struct peak_usb_device *dev, void *cmd_tail)
|
|||
return err;
|
||||
}
|
||||
|
||||
static int pcan_usb_fd_read_fwinfo(struct peak_usb_device *dev,
|
||||
struct pcan_ufd_fw_info *fw_info)
|
||||
{
|
||||
return pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO,
|
||||
PCAN_USBPRO_INFO_FW,
|
||||
fw_info,
|
||||
sizeof(*fw_info));
|
||||
}
|
||||
|
||||
/* build the commands list in the given buffer, to enter operational mode */
|
||||
static int pcan_usb_fd_build_restart_cmd(struct peak_usb_device *dev, u8 *buf)
|
||||
{
|
||||
|
@ -434,6 +452,34 @@ static int pcan_usb_fd_set_bittiming_fast(struct peak_usb_device *dev,
|
|||
return pcan_usb_fd_send_cmd(dev, ++cmd);
|
||||
}
|
||||
|
||||
/* read user CAN channel id from device */
|
||||
static int pcan_usb_fd_get_can_channel_id(struct peak_usb_device *dev,
|
||||
u32 *can_ch_id)
|
||||
{
|
||||
int err;
|
||||
struct pcan_usb_fd_if *usb_if = pcan_usb_fd_dev_if(dev);
|
||||
|
||||
err = pcan_usb_fd_read_fwinfo(dev, &usb_if->fw_info);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
*can_ch_id = le32_to_cpu(usb_if->fw_info.dev_id[dev->ctrl_idx]);
|
||||
return err;
|
||||
}
|
||||
|
||||
/* set a new CAN channel id in the flash memory of the device */
|
||||
static int pcan_usb_fd_set_can_channel_id(struct peak_usb_device *dev, u32 can_ch_id)
|
||||
{
|
||||
struct pcan_ufd_device_id *cmd = pcan_usb_fd_cmd_buffer(dev);
|
||||
|
||||
cmd->opcode_channel = pucan_cmd_opcode_channel(dev->ctrl_idx,
|
||||
PCAN_UFD_CMD_DEVID_SET);
|
||||
cmd->device_id = cpu_to_le32(can_ch_id);
|
||||
|
||||
/* send the command */
|
||||
return pcan_usb_fd_send_cmd(dev, ++cmd);
|
||||
}
|
||||
|
||||
/* handle restart but in asynchronously way
|
||||
* (uses PCAN-USB Pro code to complete asynchronous request)
|
||||
*/
|
||||
|
@ -907,10 +953,7 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev)
|
|||
|
||||
fw_info = &pdev->usb_if->fw_info;
|
||||
|
||||
err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO,
|
||||
PCAN_USBPRO_INFO_FW,
|
||||
fw_info,
|
||||
sizeof(*fw_info));
|
||||
err = pcan_usb_fd_read_fwinfo(dev, fw_info);
|
||||
if (err) {
|
||||
dev_err(dev->netdev->dev.parent,
|
||||
"unable to read %s firmware info (err %d)\n",
|
||||
|
@ -972,7 +1015,7 @@ static int pcan_usb_fd_init(struct peak_usb_device *dev)
|
|||
}
|
||||
|
||||
pdev->usb_if->dev[dev->ctrl_idx] = dev;
|
||||
dev->device_number =
|
||||
dev->can_channel_id =
|
||||
le32_to_cpu(pdev->usb_if->fw_info.dev_id[dev->ctrl_idx]);
|
||||
|
||||
/* if vendor rsp is of type 2, then it contains EP numbers to
|
||||
|
@ -1081,6 +1124,9 @@ static int pcan_usb_fd_set_phys_id(struct net_device *netdev,
|
|||
static const struct ethtool_ops pcan_usb_fd_ethtool_ops = {
|
||||
.set_phys_id = pcan_usb_fd_set_phys_id,
|
||||
.get_ts_info = pcan_get_ts_info,
|
||||
.get_eeprom_len = peak_usb_get_eeprom_len,
|
||||
.get_eeprom = peak_usb_get_eeprom,
|
||||
.set_eeprom = peak_usb_set_eeprom,
|
||||
};
|
||||
|
||||
/* describes the PCAN-USB FD adapter */
|
||||
|
@ -1148,6 +1194,8 @@ const struct peak_usb_adapter pcan_usb_fd = {
|
|||
.dev_set_bus = pcan_usb_fd_set_bus,
|
||||
.dev_set_bittiming = pcan_usb_fd_set_bittiming_slow,
|
||||
.dev_set_data_bittiming = pcan_usb_fd_set_bittiming_fast,
|
||||
.dev_get_can_channel_id = pcan_usb_fd_get_can_channel_id,
|
||||
.dev_set_can_channel_id = pcan_usb_fd_set_can_channel_id,
|
||||
.dev_decode_buf = pcan_usb_fd_decode_buf,
|
||||
.dev_start = pcan_usb_fd_start,
|
||||
.dev_stop = pcan_usb_fd_stop,
|
||||
|
@ -1222,6 +1270,8 @@ const struct peak_usb_adapter pcan_usb_chip = {
|
|||
.dev_set_bus = pcan_usb_fd_set_bus,
|
||||
.dev_set_bittiming = pcan_usb_fd_set_bittiming_slow,
|
||||
.dev_set_data_bittiming = pcan_usb_fd_set_bittiming_fast,
|
||||
.dev_get_can_channel_id = pcan_usb_fd_get_can_channel_id,
|
||||
.dev_set_can_channel_id = pcan_usb_fd_set_can_channel_id,
|
||||
.dev_decode_buf = pcan_usb_fd_decode_buf,
|
||||
.dev_start = pcan_usb_fd_start,
|
||||
.dev_stop = pcan_usb_fd_stop,
|
||||
|
@ -1296,6 +1346,8 @@ const struct peak_usb_adapter pcan_usb_pro_fd = {
|
|||
.dev_set_bus = pcan_usb_fd_set_bus,
|
||||
.dev_set_bittiming = pcan_usb_fd_set_bittiming_slow,
|
||||
.dev_set_data_bittiming = pcan_usb_fd_set_bittiming_fast,
|
||||
.dev_get_can_channel_id = pcan_usb_fd_get_can_channel_id,
|
||||
.dev_set_can_channel_id = pcan_usb_fd_set_can_channel_id,
|
||||
.dev_decode_buf = pcan_usb_fd_decode_buf,
|
||||
.dev_start = pcan_usb_fd_start,
|
||||
.dev_stop = pcan_usb_fd_stop,
|
||||
|
@ -1370,6 +1422,8 @@ const struct peak_usb_adapter pcan_usb_x6 = {
|
|||
.dev_set_bus = pcan_usb_fd_set_bus,
|
||||
.dev_set_bittiming = pcan_usb_fd_set_bittiming_slow,
|
||||
.dev_set_data_bittiming = pcan_usb_fd_set_bittiming_fast,
|
||||
.dev_get_can_channel_id = pcan_usb_fd_get_can_channel_id,
|
||||
.dev_set_can_channel_id = pcan_usb_fd_set_can_channel_id,
|
||||
.dev_decode_buf = pcan_usb_fd_decode_buf,
|
||||
.dev_start = pcan_usb_fd_start,
|
||||
.dev_stop = pcan_usb_fd_stop,
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
* Copyright (C) 2003-2011 PEAK System-Technik GmbH
|
||||
* Copyright (C) 2011-2012 Stephane Grosjean <s.grosjean@peak-system.com>
|
||||
*/
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/ethtool.h>
|
||||
|
||||
#include <linux/can.h>
|
||||
#include <linux/can/dev.h>
|
||||
|
@ -76,6 +76,7 @@ static u16 pcan_usb_pro_sizeof_rec[256] = {
|
|||
[PCAN_USBPRO_SETFILTR] = sizeof(struct pcan_usb_pro_filter),
|
||||
[PCAN_USBPRO_SETTS] = sizeof(struct pcan_usb_pro_setts),
|
||||
[PCAN_USBPRO_GETDEVID] = sizeof(struct pcan_usb_pro_devid),
|
||||
[PCAN_USBPRO_SETDEVID] = sizeof(struct pcan_usb_pro_devid),
|
||||
[PCAN_USBPRO_SETLED] = sizeof(struct pcan_usb_pro_setled),
|
||||
[PCAN_USBPRO_RXMSG8] = sizeof(struct pcan_usb_pro_rxmsg),
|
||||
[PCAN_USBPRO_RXMSG4] = sizeof(struct pcan_usb_pro_rxmsg) - 4,
|
||||
|
@ -149,6 +150,7 @@ static int pcan_msg_add_rec(struct pcan_usb_pro_msg *pm, int id, ...)
|
|||
|
||||
case PCAN_USBPRO_SETBTR:
|
||||
case PCAN_USBPRO_GETDEVID:
|
||||
case PCAN_USBPRO_SETDEVID:
|
||||
*pc++ = va_arg(ap, int);
|
||||
pc += 2;
|
||||
*(__le32 *)pc = cpu_to_le32(va_arg(ap, u32));
|
||||
|
@ -419,8 +421,8 @@ static int pcan_usb_pro_set_led(struct peak_usb_device *dev, u8 mode,
|
|||
return pcan_usb_pro_send_cmd(dev, &um);
|
||||
}
|
||||
|
||||
static int pcan_usb_pro_get_device_id(struct peak_usb_device *dev,
|
||||
u32 *device_id)
|
||||
static int pcan_usb_pro_get_can_channel_id(struct peak_usb_device *dev,
|
||||
u32 *can_ch_id)
|
||||
{
|
||||
struct pcan_usb_pro_devid *pdn;
|
||||
struct pcan_usb_pro_msg um;
|
||||
|
@ -439,11 +441,23 @@ static int pcan_usb_pro_get_device_id(struct peak_usb_device *dev,
|
|||
return err;
|
||||
|
||||
pdn = (struct pcan_usb_pro_devid *)pc;
|
||||
*device_id = le32_to_cpu(pdn->dev_num);
|
||||
*can_ch_id = le32_to_cpu(pdn->dev_num);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int pcan_usb_pro_set_can_channel_id(struct peak_usb_device *dev,
|
||||
u32 can_ch_id)
|
||||
{
|
||||
struct pcan_usb_pro_msg um;
|
||||
|
||||
pcan_msg_init_empty(&um, dev->cmd_buf, PCAN_USB_MAX_CMD_LEN);
|
||||
pcan_msg_add_rec(&um, PCAN_USBPRO_SETDEVID, dev->ctrl_idx,
|
||||
can_ch_id);
|
||||
|
||||
return pcan_usb_pro_send_cmd(dev, &um);
|
||||
}
|
||||
|
||||
static int pcan_usb_pro_set_bittiming(struct peak_usb_device *dev,
|
||||
struct can_bittiming *bt)
|
||||
{
|
||||
|
@ -1023,6 +1037,9 @@ static int pcan_usb_pro_set_phys_id(struct net_device *netdev,
|
|||
static const struct ethtool_ops pcan_usb_pro_ethtool_ops = {
|
||||
.set_phys_id = pcan_usb_pro_set_phys_id,
|
||||
.get_ts_info = pcan_get_ts_info,
|
||||
.get_eeprom_len = peak_usb_get_eeprom_len,
|
||||
.get_eeprom = peak_usb_get_eeprom,
|
||||
.set_eeprom = peak_usb_set_eeprom,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -1076,7 +1093,8 @@ const struct peak_usb_adapter pcan_usb_pro = {
|
|||
.dev_free = pcan_usb_pro_free,
|
||||
.dev_set_bus = pcan_usb_pro_set_bus,
|
||||
.dev_set_bittiming = pcan_usb_pro_set_bittiming,
|
||||
.dev_get_device_id = pcan_usb_pro_get_device_id,
|
||||
.dev_get_can_channel_id = pcan_usb_pro_get_can_channel_id,
|
||||
.dev_set_can_channel_id = pcan_usb_pro_set_can_channel_id,
|
||||
.dev_decode_buf = pcan_usb_pro_decode_buf,
|
||||
.dev_encode_msg = pcan_usb_pro_encode_msg,
|
||||
.dev_start = pcan_usb_pro_start,
|
||||
|
|
|
@ -62,6 +62,7 @@ struct __packed pcan_usb_pro_fwinfo {
|
|||
#define PCAN_USBPRO_SETBTR 0x02
|
||||
#define PCAN_USBPRO_SETBUSACT 0x04
|
||||
#define PCAN_USBPRO_SETSILENT 0x05
|
||||
#define PCAN_USBPRO_SETDEVID 0x06
|
||||
#define PCAN_USBPRO_SETFILTR 0x0a
|
||||
#define PCAN_USBPRO_SETTS 0x10
|
||||
#define PCAN_USBPRO_GETDEVID 0x12
|
||||
|
|
|
@ -116,7 +116,7 @@ struct can_tdc_const {
|
|||
|
||||
#ifdef CONFIG_CAN_CALC_BITTIMING
|
||||
int can_calc_bittiming(const struct net_device *dev, struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc);
|
||||
const struct can_bittiming_const *btc, struct netlink_ext_ack *extack);
|
||||
|
||||
void can_calc_tdco(struct can_tdc *tdc, const struct can_tdc_const *tdc_const,
|
||||
const struct can_bittiming *dbt,
|
||||
|
@ -138,10 +138,16 @@ can_calc_tdco(struct can_tdc *tdc, const struct can_tdc_const *tdc_const,
|
|||
}
|
||||
#endif /* CONFIG_CAN_CALC_BITTIMING */
|
||||
|
||||
void can_sjw_set_default(struct can_bittiming *bt);
|
||||
|
||||
int can_sjw_check(const struct net_device *dev, const struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc, struct netlink_ext_ack *extack);
|
||||
|
||||
int can_get_bittiming(const struct net_device *dev, struct can_bittiming *bt,
|
||||
const struct can_bittiming_const *btc,
|
||||
const u32 *bitrate_const,
|
||||
const unsigned int bitrate_const_cnt);
|
||||
const unsigned int bitrate_const_cnt,
|
||||
struct netlink_ext_ack *extack);
|
||||
|
||||
/*
|
||||
* can_bit_time() - Duration of one bit
|
||||
|
|
|
@ -1139,6 +1139,13 @@ static int cgw_create_job(struct sk_buff *skb, struct nlmsghdr *nlh,
|
|||
if (gwj->dst.dev->type != ARPHRD_CAN)
|
||||
goto out;
|
||||
|
||||
/* is sending the skb back to the incoming interface intended? */
|
||||
if (gwj->src.dev == gwj->dst.dev &&
|
||||
!(gwj->flags & CGW_FLAGS_CAN_IIF_TX_OK)) {
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
err = cgw_register_filter(net, gwj);
|
||||
|
|
|
@ -1220,6 +1220,9 @@ static int isotp_bind(struct socket *sock, struct sockaddr *uaddr, int len)
|
|||
if (len < ISOTP_MIN_NAMELEN)
|
||||
return -EINVAL;
|
||||
|
||||
if (addr->can_family != AF_CAN)
|
||||
return -EINVAL;
|
||||
|
||||
/* sanitize tx CAN identifier */
|
||||
if (tx_id & CAN_EFF_FLAG)
|
||||
tx_id &= (CAN_EFF_FLAG | CAN_EFF_MASK);
|
||||
|
|
Loading…
Reference in New Issue