[PATCH v2 4/6] net: can: flexcan: Add provision for variable payload size

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Till now the flexcan module supported 8 byte payload size as per CAN 2.0
specifications.
But now upcoming flexcan module in NXP LX2160A SOC supports CAN FD protocol
too.The Message buffers need to be configured to have payload size greater
than 8 bytes (if flexcan module supports it)

Therefore, added provision in the driver for payload size to be variable.
BUT, limit the only possible payload value to be 8, because the CAN FD
changes are not in place yet.

Signed-off-by: Pankaj Bansal <pankaj.bansal@xxxxxxx>
---

Notes:
    V2:
    - Change data from u32 to __be32 in flexcan_mailbox_read
    - Added function flexcan_get_mb to get mailbox address from mailbox number

 drivers/net/can/flexcan.c | 91 +++++++++++++++++++++++++++----------
 1 file changed, 67 insertions(+), 24 deletions(-)

diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index 755a761eef02..54eb1039ad20 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -140,7 +140,6 @@
 #define FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP	0
 #define FLEXCAN_TX_MB_OFF_TIMESTAMP		1
 #define FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST	(FLEXCAN_TX_MB_OFF_TIMESTAMP + 1)
-#define FLEXCAN_RX_MB_OFF_TIMESTAMP_LAST	63
 #define FLEXCAN_IFLAG_MB(x)		BIT(x)
 #define FLEXCAN_IFLAG_RX_FIFO_OVERFLOW	BIT(7)
 #define FLEXCAN_IFLAG_RX_FIFO_WARN	BIT(6)
@@ -195,7 +194,7 @@
 struct flexcan_mb {
 	u32 can_ctrl;
 	u32 can_id;
-	u32 data[2];
+	u32 data[];
 };
 
 /* Structure of the hardware registers */
@@ -224,7 +223,7 @@ struct flexcan_regs {
 	u32 rxfgmask;		/* 0x48 */
 	u32 rxfir;		/* 0x4c */
 	u32 _reserved3[12];	/* 0x50 */
-	struct flexcan_mb mb[64];	/* 0x80 */
+	u32 mb[256];		/* 0x80 */
 	/* FIFO-mode:
 	 *			MB
 	 * 0x080...0x08f	0	RX message buffer
@@ -252,6 +251,7 @@ struct flexcan_regs {
 
 struct flexcan_devtype_data {
 	u32 quirks;		/* quirks needed for different IP cores */
+	u8 payload_size;	/* payload size in each MB */
 };
 
 struct flexcan_priv {
@@ -280,32 +280,38 @@ static const struct flexcan_devtype_data fsl_p1010_devtype_data = {
 	.quirks = FLEXCAN_QUIRK_BROKEN_WERR_STATE |
 		FLEXCAN_QUIRK_BROKEN_PERR_STATE |
 		FLEXCAN_QUIRK_DEFAULT_BIG_ENDIAN,
+	.payload_size = CAN_MAX_DLEN,
 };
 
 static const struct flexcan_devtype_data fsl_imx25_devtype_data = {
 	.quirks = FLEXCAN_QUIRK_BROKEN_WERR_STATE |
 		FLEXCAN_QUIRK_BROKEN_PERR_STATE,
+	.payload_size = CAN_MAX_DLEN,
 };
 
 static const struct flexcan_devtype_data fsl_imx28_devtype_data = {
 	.quirks = FLEXCAN_QUIRK_BROKEN_PERR_STATE,
+	.payload_size = CAN_MAX_DLEN,
 };
 
 static const struct flexcan_devtype_data fsl_imx6q_devtype_data = {
 	.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
 		FLEXCAN_QUIRK_USE_OFF_TIMESTAMP | FLEXCAN_QUIRK_BROKEN_PERR_STATE,
+	.payload_size = CAN_MAX_DLEN,
 };
 
 static const struct flexcan_devtype_data fsl_vf610_devtype_data = {
 	.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
 		FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_USE_OFF_TIMESTAMP |
 		FLEXCAN_QUIRK_BROKEN_PERR_STATE,
+	.payload_size = CAN_MAX_DLEN,
 };
 
 static const struct flexcan_devtype_data fsl_ls1021a_r2_devtype_data = {
 	.quirks = FLEXCAN_QUIRK_DISABLE_RXFG | FLEXCAN_QUIRK_ENABLE_EACEN_RRS |
 		FLEXCAN_QUIRK_DISABLE_MECR | FLEXCAN_QUIRK_BROKEN_PERR_STATE |
 		FLEXCAN_QUIRK_USE_OFF_TIMESTAMP,
+	.payload_size = CAN_MAX_DLEN,
 };
 
 static const struct can_bittiming_const flexcan_bittiming_const = {
@@ -353,6 +359,22 @@ static inline void flexcan_write_le(u32 val, void __iomem *addr)
 	iowrite32(val, addr);
 }
 
+static struct flexcan_mb *flexcan_get_mb(const struct flexcan_priv *priv,
+					 u8 mb_index)
+{
+	u8 mb_size;
+	u8 mb_count;
+
+	mb_size = sizeof(struct flexcan_mb) + priv->devtype_data->payload_size;
+	mb_count = (sizeof(priv->regs->mb) / mb_size);
+
+	if (mb_index >= mb_count)
+		return NULL;
+
+	return (struct flexcan_mb __iomem *)((u8 *)&priv->regs->mb +
+					     (mb_size * mb_index));
+}
+
 static inline void flexcan_error_irq_enable(const struct flexcan_priv *priv)
 {
 	struct flexcan_regs __iomem *regs = priv->regs;
@@ -519,6 +541,7 @@ static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *de
 	u32 can_id;
 	u32 data;
 	u32 ctrl = FLEXCAN_MB_CODE_TX_DATA | (cf->can_dlc << 16);
+	u8 can_dlc_dword, i;
 
 	if (can_dropped_invalid_skb(dev, skb))
 		return NETDEV_TX_OK;
@@ -535,13 +558,10 @@ static netdev_tx_t flexcan_start_xmit(struct sk_buff *skb, struct net_device *de
 	if (cf->can_id & CAN_RTR_FLAG)
 		ctrl |= FLEXCAN_MB_CNT_RTR;
 
-	if (cf->can_dlc > 0) {
-		data = be32_to_cpup((__be32 *)&cf->data[0]);
-		priv->write(data, &priv->tx_mb->data[0]);
-	}
-	if (cf->can_dlc > 4) {
-		data = be32_to_cpup((__be32 *)&cf->data[4]);
-		priv->write(data, &priv->tx_mb->data[1]);
+	can_dlc_dword = (cf->can_dlc + sizeof(u32) - 1) / sizeof(u32);
+	for (i = 0; i < can_dlc_dword; i++) {
+		data = be32_to_cpup((__be32 *)&cf->data[(i * sizeof(u32))]);
+		priv->write(data, &priv->tx_mb->data[i]);
 	}
 
 	can_put_echo_skb(skb, dev, 0);
@@ -666,8 +686,12 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
 {
 	struct flexcan_priv *priv = rx_offload_to_priv(offload);
 	struct flexcan_regs __iomem *regs = priv->regs;
-	struct flexcan_mb __iomem *mb = &regs->mb[n];
+	struct flexcan_mb __iomem *mb;
 	u32 reg_ctrl, reg_id, reg_iflag1;
+	__be32 data;
+	u8 can_dlc_dword, i;
+
+	mb = flexcan_get_mb(priv, n);
 
 	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
 		u32 code;
@@ -708,8 +732,11 @@ static unsigned int flexcan_mailbox_read(struct can_rx_offload *offload,
 		cf->can_id |= CAN_RTR_FLAG;
 	cf->can_dlc = get_can_dlc((reg_ctrl >> 16) & 0xf);
 
-	*(__be32 *)(cf->data + 0) = cpu_to_be32(priv->read(&mb->data[0]));
-	*(__be32 *)(cf->data + 4) = cpu_to_be32(priv->read(&mb->data[1]));
+	can_dlc_dword = (cf->can_dlc + sizeof(u32) - 1) / sizeof(u32);
+	for (i = 0; i < can_dlc_dword; i++) {
+		data = cpu_to_be32(priv->read(&mb->data[i]));
+		*(__be32 *)(cf->data + (i * sizeof(u32))) = data;
+	}
 
 	/* mark as read */
 	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
@@ -906,6 +933,10 @@ static int flexcan_chip_start(struct net_device *dev)
 	struct flexcan_regs __iomem *regs = priv->regs;
 	u32 reg_mcr, reg_ctrl, reg_ctrl2, reg_mecr;
 	int err, i;
+	struct flexcan_mb __iomem *mb;
+	u8 mb_size;
+
+	mb_size = sizeof(struct flexcan_mb) + priv->devtype_data->payload_size;
 
 	/* enable module */
 	err = flexcan_chip_enable(priv);
@@ -987,15 +1018,18 @@ static int flexcan_chip_start(struct net_device *dev)
 	}
 
 	/* clear and invalidate all mailboxes first */
-	for (i = priv->tx_mb_idx; i < ARRAY_SIZE(regs->mb); i++) {
-		priv->write(FLEXCAN_MB_CODE_RX_INACTIVE,
-			    &regs->mb[i].can_ctrl);
+	for (i = priv->tx_mb_idx; i < (sizeof(regs->mb) / mb_size); i++) {
+		mb = flexcan_get_mb(priv, i);
+		priv->write(FLEXCAN_MB_CODE_RX_INACTIVE, &mb->can_ctrl);
 	}
 
 	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
-		for (i = priv->offload.mb_first; i <= priv->offload.mb_last; i++)
-			priv->write(FLEXCAN_MB_CODE_RX_EMPTY,
-				    &regs->mb[i].can_ctrl);
+		for (i = priv->offload.mb_first;
+		     i <= priv->offload.mb_last;
+		     i++) {
+			mb = flexcan_get_mb(priv, i);
+			priv->write(FLEXCAN_MB_CODE_RX_EMPTY, &mb->can_ctrl);
+		}
 	}
 
 	/* Errata ERR005829: mark first TX mailbox as INACTIVE */
@@ -1015,7 +1049,7 @@ static int flexcan_chip_start(struct net_device *dev)
 		priv->write(0x0, &regs->rxfgmask);
 
 	/* clear acceptance filters */
-	for (i = 0; i < ARRAY_SIZE(regs->mb); i++)
+	for (i = 0; i < ARRAY_SIZE(regs->rximr); i++)
 		priv->write(0, &regs->rximr[i]);
 
 	/* On Vybrid, disable memory error detection interrupts
@@ -1279,6 +1313,7 @@ static int flexcan_probe(struct platform_device *pdev)
 	struct flexcan_regs __iomem *regs;
 	int err, irq;
 	u32 clock_freq = 0;
+	u8 mb_size;
 
 	reg_xceiver = devm_regulator_get(&pdev->dev, "xceiver");
 	if (PTR_ERR(reg_xceiver) == -EPROBE_DEFER)
@@ -1346,6 +1381,14 @@ static int flexcan_probe(struct platform_device *pdev)
 		priv->write = flexcan_write_le;
 	}
 
+	if (devtype_data->payload_size != CAN_MAX_DLEN) {
+		dev_err(&pdev->dev, "payload_size %d not supported\n",
+			devtype_data->payload_size);
+		err = -ENODEV;
+		goto failed_register;
+	}
+	mb_size = sizeof(struct flexcan_mb) + devtype_data->payload_size;
+
 	priv->can.clock.freq = clock_freq;
 	priv->can.bittiming_const = &flexcan_bittiming_const;
 	priv->can.do_set_mode = flexcan_set_mode;
@@ -1361,12 +1404,12 @@ static int flexcan_probe(struct platform_device *pdev)
 
 	if (priv->devtype_data->quirks & FLEXCAN_QUIRK_USE_OFF_TIMESTAMP) {
 		priv->tx_mb_idx = FLEXCAN_TX_MB_OFF_TIMESTAMP;
-		priv->tx_mb_reserved = &regs->mb[FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP];
+		priv->tx_mb_reserved = flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_OFF_TIMESTAMP);
 	} else {
 		priv->tx_mb_idx = FLEXCAN_TX_MB_OFF_FIFO;
-		priv->tx_mb_reserved = &regs->mb[FLEXCAN_TX_MB_RESERVED_OFF_FIFO];
+		priv->tx_mb_reserved = flexcan_get_mb(priv, FLEXCAN_TX_MB_RESERVED_OFF_FIFO);
 	}
-	priv->tx_mb = &regs->mb[priv->tx_mb_idx];
+	priv->tx_mb = flexcan_get_mb(priv, priv->tx_mb_idx);
 
 	priv->reg_imask1_default = FLEXCAN_IFLAG_MB(priv->tx_mb_idx);
 	priv->reg_imask2_default = 0;
@@ -1377,7 +1420,7 @@ static int flexcan_probe(struct platform_device *pdev)
 		u64 imask;
 
 		priv->offload.mb_first = FLEXCAN_RX_MB_OFF_TIMESTAMP_FIRST;
-		priv->offload.mb_last = FLEXCAN_RX_MB_OFF_TIMESTAMP_LAST;
+		priv->offload.mb_last = (sizeof(regs->mb) / mb_size) - 1;
 
 		imask = GENMASK_ULL(priv->offload.mb_last, priv->offload.mb_first);
 		priv->reg_imask1_default |= imask;
-- 
2.17.1

--
To unsubscribe from this list: send the line "unsubscribe linux-can" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Automotive Discussions]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux]     [Linux OMAP]     [Linux MIPS]     [eCos]     [Asterisk Internet PBX]     [Linux API]     [CAN Bus]

  Powered by Linux