npcm7xx-emc: diorite c0 workaround

Remove garbage byte sent by c0 and re-calculate checksum.
This assumes that there are always 1 byte garbage, which is the case
based on current testing.

Change-Id: I92465e3350ce606e288853ea040ba2be88a99e8f
Signed-off-by: Yuxiao Zhang <yuxiaozhang@google.com>
(cherry picked from commit 90f2cffc710aafb6ceec75bf0d7503506fbaaed5)
(cherry picked from commit 141daea52e9e3ffad6db25bac24f404d1726fcfa)
diff --git a/recipes-kernel/linux/5.15/0001-Diorite-workaround-for-c0-card.patch b/recipes-kernel/linux/5.15/0001-Diorite-workaround-for-c0-card.patch
new file mode 100644
index 0000000..d87ea97
--- /dev/null
+++ b/recipes-kernel/linux/5.15/0001-Diorite-workaround-for-c0-card.patch
@@ -0,0 +1,110 @@
+From 6394781fddc8bb2d48f08994595fff4e77c238e5 Mon Sep 17 00:00:00 2001
+From: invalid_git config <unknown@unknown>
+Date: Tue, 29 Aug 2023 20:48:42 +0000
+Subject: [PATCH] Diorite workaround for c0 card
+
+Diorite c0 card has one dribble bytes at the end of the packet, this
+patch is a workaround of removing it and redo the checksum.
+---
+ drivers/net/ethernet/nuvoton/npcm7xx_emc.c | 50 ++++++++++++++++++++--
+ 1 file changed, 47 insertions(+), 3 deletions(-)
+
+diff --git a/drivers/net/ethernet/nuvoton/npcm7xx_emc.c b/drivers/net/ethernet/nuvoton/npcm7xx_emc.c
+index 2c58a82a56fd..a2ce9d976d18 100644
+--- a/drivers/net/ethernet/nuvoton/npcm7xx_emc.c
++++ b/drivers/net/ethernet/nuvoton/npcm7xx_emc.c
+@@ -92,6 +92,7 @@ static struct dentry *npcm7xx_fs_dir;
+ #define MCMDR_RXON		BIT(0)
+ #define MCMDR_ALP		BIT(1)
+ #define MCMDR_ACP		BIT(3)
++#define MCMDR_AEP               BIT(4)
+ #define MCMDR_SPCRC		BIT(5)
+ #define MCMDR_TXON		BIT(8)
+ #define MCMDR_NDEF		BIT(9)
+@@ -1059,6 +1060,12 @@ static void npcm7xx_rx_enable(struct net_device *netdev)
+ 	struct npcm7xx_ether *ether = netdev_priv(netdev);
+ 
+ 	/* enable RX */
++	writel(readl((ether->reg + REG_MCMDR)) & ~(MCMDR_SPCRC),
++		(ether->reg + REG_MCMDR));
++
++	writel(readl((ether->reg + REG_MCMDR)) | (MCMDR_AEP),
++		(ether->reg + REG_MCMDR));
++
+ 	writel(readl((ether->reg + REG_MCMDR)) | MCMDR_RXON,
+ 	       (ether->reg + REG_MCMDR));
+ }
+@@ -1585,18 +1592,18 @@ static int npcm7xx_poll(struct napi_struct *napi, int budget)
+ 		 */
+ 		if (likely((status & (RXDS_RXGD | RXDS_CRCE | RXDS_ALIE |
+ 				      RXDS_RP | (IS_VLAN ? 0 : RXDS_PTLE))) ==
+-			   RXDS_RXGD) && likely(length <= MAX_PACKET_SIZE)) {
++			   RXDS_RXGD) && likely(length <= MAX_PACKET_SIZE_W_CRC)) {
+ 			if (s) {
+ 				dma_unmap_single(&pdev->dev,
+ 						(dma_addr_t)le32_to_cpu(rxbd->buffer),
+ 						roundup(MAX_PACKET_SIZE_W_CRC, 4),
+ 						DMA_FROM_DEVICE);
+ 
+-				skb_put(s, length);
++				skb_put(s, length - 4);
+ 				s->protocol = eth_type_trans(s, netdev);
+ 				netif_receive_skb(s);
+ 				ether->stats.rx_packets++;
+-				ether->stats.rx_bytes += length;
++				ether->stats.rx_bytes += (length - 4);
+ 			} else
+ 				ether->stats.rx_dropped++;
+ 			rx_cnt++;
+@@ -1605,6 +1609,40 @@ static int npcm7xx_poll(struct napi_struct *napi, int budget)
+ 			/* now we allocate new skb instead if the used one. */
+ 			get_new_skb(netdev, ether->cur_rx);
+ 		} else {
++			if (likely((status & (RXDS_RXGD | RXDS_RP | RXDS_CRCE)) == (RXDS_RXGD | RXDS_CRCE))) {
++				if (s) {
++					dma_unmap_single(&pdev->dev,
++							 (dma_addr_t)le32_to_cpu(rxbd->buffer),
++							 roundup(MAX_PACKET_SIZE_W_CRC, 4),
++							 DMA_FROM_DEVICE);
++					skb_put(s, length - 1);
++					uint8_t dribble = 1;
++					for (dribble = 1; dribble <= 2; ++dribble) {
++						uint32_t crc = ether_crc_le(length - 4 - dribble, s->data) ^ 0xFFFFFFFF;
++						if (likely(crc == get_unaligned_le32(s->data + length - 4 - dribble))) {
++							break;
++						}
++					}
++					if (likely(dribble <= 2)) {
++						skb_trim(s, length - 4 - dribble);
++						s->protocol = eth_type_trans(s, netdev);
++						netif_receive_skb(s);
++						ether->stats.rx_packets++;
++						ether->stats.rx_bytes += (length - 4 - dribble);
++					} else {
++						dev_kfree_skb_any(s);
++						get_new_skb(netdev, ether->cur_rx);
++						goto rx_error;
++					}
++				} else {
++					ether->stats.rx_dropped++;
++				}
++				rx_cnt++;
++				ether->rx_count_pool++;
++				get_new_skb(netdev, ether->cur_rx);
++				goto rx_poll_done;
++			}
++rx_error:
+ 			ether->rx_err_count++;
+ 			ether->stats.rx_errors++;
+ 			dev_dbg(&pdev->dev, "rx_errors = %lu status = 0x%08X\n",
+@@ -1630,6 +1671,7 @@ static int npcm7xx_poll(struct napi_struct *napi, int budget)
+ 			}
+ 		}
+ 
++rx_poll_done:
+ 		/* make sure other values are set before we set owner */
+ 		wmb();
+ 
+-- 
+2.42.0.459.ge4e396fd5e-goog
+
diff --git a/recipes-kernel/linux/linux-gbmc_5.15.bb b/recipes-kernel/linux/linux-gbmc_5.15.bb
index 2e2d4a0..6be0306 100644
--- a/recipes-kernel/linux/linux-gbmc_5.15.bb
+++ b/recipes-kernel/linux/linux-gbmc_5.15.bb
@@ -5,11 +5,17 @@
 SRCREV = "1720a480503b8bcf69419c11af5fdaf54fa43d03"
 LIC_FILES_CHKSUM = "file://COPYING;md5=6bc538ed5bd9a7fc9398086aedcd7e46"
 
+PACKAGECONFIG[diorite_c0] = ""
+
 FILESEXTRAPATHS:prepend := "${THISDIR}/5.15:"
 SRC_URI += " \
   file://DOWNSTREAM_0002-mtd-spi-nor-macronix-Add-google-compatible-flash-IDs.patch \
   "
 
+SRC_URI:append:npcm7xx =  "\
+  ${@bb.utils.contains('PACKAGECONFIG', 'diorite_c0', 'file://0001-Diorite-workaround-for-c0-card.patch', '', d)} \
+  "
+
 SRC_URI:append:aspeed-g6 = " \
   file://0001-net-ftgmac100-Support-for-fixed-PHYs.patch \
   file://DOWNSTREAM_0002-kernel-Ensure-only-3-byte-read-command-can-be-sent.patch \