--- /dev/null
+From e5e884b42639c74b5b57dc277909915c0aefc8bb Mon Sep 17 00:00:00 2001
+From: Wen Huang <huangwenabc@gmail.com>
+Date: Thu, 28 Nov 2019 18:51:04 +0800
+Subject: libertas: Fix two buffer overflows at parsing bss descriptor
+
+From: Wen Huang <huangwenabc@gmail.com>
+
+commit e5e884b42639c74b5b57dc277909915c0aefc8bb upstream.
+
+add_ie_rates() copys rates without checking the length
+in bss descriptor from remote AP.when victim connects to
+remote attacker, this may trigger buffer overflow.
+lbs_ibss_join_existing() copys rates without checking the length
+in bss descriptor from remote IBSS node.when victim connects to
+remote attacker, this may trigger buffer overflow.
+Fix them by putting the length check before performing copy.
+
+This fix addresses CVE-2019-14896 and CVE-2019-14897.
+This also fix build warning of mixed declarations and code.
+
+Reported-by: kbuild test robot <lkp@intel.com>
+Signed-off-by: Wen Huang <huangwenabc@gmail.com>
+Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/wireless/marvell/libertas/cfg.c | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+--- a/drivers/net/wireless/marvell/libertas/cfg.c
++++ b/drivers/net/wireless/marvell/libertas/cfg.c
+@@ -273,6 +273,10 @@ add_ie_rates(u8 *tlv, const u8 *ie, int
+ int hw, ap, ap_max = ie[1];
+ u8 hw_rate;
+
++ if (ap_max > MAX_RATES) {
++ lbs_deb_assoc("invalid rates\n");
++ return tlv;
++ }
+ /* Advance past IE header */
+ ie += 2;
+
+@@ -1717,6 +1721,9 @@ static int lbs_ibss_join_existing(struct
+ struct cmd_ds_802_11_ad_hoc_join cmd;
+ u8 preamble = RADIO_PREAMBLE_SHORT;
+ int ret = 0;
++ int hw, i;
++ u8 rates_max;
++ u8 *rates;
+
+ /* TODO: set preamble based on scan result */
+ ret = lbs_set_radio(priv, preamble, 1);
+@@ -1775,9 +1782,12 @@ static int lbs_ibss_join_existing(struct
+ if (!rates_eid) {
+ lbs_add_rates(cmd.bss.rates);
+ } else {
+- int hw, i;
+- u8 rates_max = rates_eid[1];
+- u8 *rates = cmd.bss.rates;
++ rates_max = rates_eid[1];
++ if (rates_max > MAX_RATES) {
++ lbs_deb_join("invalid rates");
++ goto out;
++ }
++ rates = cmd.bss.rates;
+ for (hw = 0; hw < ARRAY_SIZE(lbs_rates); hw++) {
+ u8 hw_rate = lbs_rates[hw].bitrate / 5;
+ for (i = 0; i < rates_max; i++) {
--- /dev/null
+From ee8951e56c0f960b9621636603a822811cef3158 Mon Sep 17 00:00:00 2001
+From: Hans Verkuil <hverkuil-cisco@xs4all.nl>
+Date: Sun, 10 Nov 2019 07:27:04 +0100
+Subject: media: v4l2-ioctl.c: zero reserved fields for S/TRY_FMT
+
+From: Hans Verkuil <hverkuil-cisco@xs4all.nl>
+
+commit ee8951e56c0f960b9621636603a822811cef3158 upstream.
+
+v4l2_vbi_format, v4l2_sliced_vbi_format and v4l2_sdr_format
+have a reserved array at the end that should be zeroed by drivers
+as per the V4L2 spec. Older drivers often do not do this, so just
+handle this in the core.
+
+Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
+Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/media/v4l2-core/v4l2-ioctl.c | 24 ++++++++++++------------
+ 1 file changed, 12 insertions(+), 12 deletions(-)
+
+--- a/drivers/media/v4l2-core/v4l2-ioctl.c
++++ b/drivers/media/v4l2-core/v4l2-ioctl.c
+@@ -1605,12 +1605,12 @@ static int v4l_s_fmt(const struct v4l2_i
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ if (unlikely(!ops->vidioc_s_fmt_vbi_cap))
+ break;
+- CLEAR_AFTER_FIELD(p, fmt.vbi);
++ CLEAR_AFTER_FIELD(p, fmt.vbi.flags);
+ return ops->vidioc_s_fmt_vbi_cap(file, fh, arg);
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_cap))
+ break;
+- CLEAR_AFTER_FIELD(p, fmt.sliced);
++ CLEAR_AFTER_FIELD(p, fmt.sliced.io_size);
+ return ops->vidioc_s_fmt_sliced_vbi_cap(file, fh, arg);
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ if (unlikely(!ops->vidioc_s_fmt_vid_out))
+@@ -1636,22 +1636,22 @@ static int v4l_s_fmt(const struct v4l2_i
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ if (unlikely(!ops->vidioc_s_fmt_vbi_out))
+ break;
+- CLEAR_AFTER_FIELD(p, fmt.vbi);
++ CLEAR_AFTER_FIELD(p, fmt.vbi.flags);
+ return ops->vidioc_s_fmt_vbi_out(file, fh, arg);
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ if (unlikely(!ops->vidioc_s_fmt_sliced_vbi_out))
+ break;
+- CLEAR_AFTER_FIELD(p, fmt.sliced);
++ CLEAR_AFTER_FIELD(p, fmt.sliced.io_size);
+ return ops->vidioc_s_fmt_sliced_vbi_out(file, fh, arg);
+ case V4L2_BUF_TYPE_SDR_CAPTURE:
+ if (unlikely(!ops->vidioc_s_fmt_sdr_cap))
+ break;
+- CLEAR_AFTER_FIELD(p, fmt.sdr);
++ CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize);
+ return ops->vidioc_s_fmt_sdr_cap(file, fh, arg);
+ case V4L2_BUF_TYPE_SDR_OUTPUT:
+ if (unlikely(!ops->vidioc_s_fmt_sdr_out))
+ break;
+- CLEAR_AFTER_FIELD(p, fmt.sdr);
++ CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize);
+ return ops->vidioc_s_fmt_sdr_out(file, fh, arg);
+ case V4L2_BUF_TYPE_META_CAPTURE:
+ if (unlikely(!ops->vidioc_s_fmt_meta_cap))
+@@ -1707,12 +1707,12 @@ static int v4l_try_fmt(const struct v4l2
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ if (unlikely(!ops->vidioc_try_fmt_vbi_cap))
+ break;
+- CLEAR_AFTER_FIELD(p, fmt.vbi);
++ CLEAR_AFTER_FIELD(p, fmt.vbi.flags);
+ return ops->vidioc_try_fmt_vbi_cap(file, fh, arg);
+ case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
+ if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_cap))
+ break;
+- CLEAR_AFTER_FIELD(p, fmt.sliced);
++ CLEAR_AFTER_FIELD(p, fmt.sliced.io_size);
+ return ops->vidioc_try_fmt_sliced_vbi_cap(file, fh, arg);
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+ if (unlikely(!ops->vidioc_try_fmt_vid_out))
+@@ -1738,22 +1738,22 @@ static int v4l_try_fmt(const struct v4l2
+ case V4L2_BUF_TYPE_VBI_OUTPUT:
+ if (unlikely(!ops->vidioc_try_fmt_vbi_out))
+ break;
+- CLEAR_AFTER_FIELD(p, fmt.vbi);
++ CLEAR_AFTER_FIELD(p, fmt.vbi.flags);
+ return ops->vidioc_try_fmt_vbi_out(file, fh, arg);
+ case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
+ if (unlikely(!ops->vidioc_try_fmt_sliced_vbi_out))
+ break;
+- CLEAR_AFTER_FIELD(p, fmt.sliced);
++ CLEAR_AFTER_FIELD(p, fmt.sliced.io_size);
+ return ops->vidioc_try_fmt_sliced_vbi_out(file, fh, arg);
+ case V4L2_BUF_TYPE_SDR_CAPTURE:
+ if (unlikely(!ops->vidioc_try_fmt_sdr_cap))
+ break;
+- CLEAR_AFTER_FIELD(p, fmt.sdr);
++ CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize);
+ return ops->vidioc_try_fmt_sdr_cap(file, fh, arg);
+ case V4L2_BUF_TYPE_SDR_OUTPUT:
+ if (unlikely(!ops->vidioc_try_fmt_sdr_out))
+ break;
+- CLEAR_AFTER_FIELD(p, fmt.sdr);
++ CLEAR_AFTER_FIELD(p, fmt.sdr.buffersize);
+ return ops->vidioc_try_fmt_sdr_out(file, fh, arg);
+ case V4L2_BUF_TYPE_META_CAPTURE:
+ if (unlikely(!ops->vidioc_try_fmt_meta_cap))
--- /dev/null
+From 865ad2f2201dc18685ba2686f13217f8b3a9c52c Mon Sep 17 00:00:00 2001
+From: Finn Thain <fthain@telegraphics.com.au>
+Date: Thu, 23 Jan 2020 09:07:26 +1100
+Subject: net/sonic: Add mutual exclusion for accessing shared state
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+commit 865ad2f2201dc18685ba2686f13217f8b3a9c52c upstream.
+
+The netif_stop_queue() call in sonic_send_packet() races with the
+netif_wake_queue() call in sonic_interrupt(). This causes issues
+like "NETDEV WATCHDOG: eth0 (macsonic): transmit queue 0 timed out".
+Fix this by disabling interrupts when accessing tx_skb[] and next_tx.
+Update a comment to clarify the synchronization properties.
+
+Fixes: efcce839360f ("[PATCH] macsonic/jazzsonic network drivers update")
+Tested-by: Stan Johnson <userm57@yahoo.com>
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/ethernet/natsemi/sonic.c | 49 +++++++++++++++++++++++++----------
+ drivers/net/ethernet/natsemi/sonic.h | 1
+ 2 files changed, 36 insertions(+), 14 deletions(-)
+
+--- a/drivers/net/ethernet/natsemi/sonic.c
++++ b/drivers/net/ethernet/natsemi/sonic.c
+@@ -64,6 +64,8 @@ static int sonic_open(struct net_device
+
+ netif_dbg(lp, ifup, dev, "%s: initializing sonic driver\n", __func__);
+
++ spin_lock_init(&lp->lock);
++
+ for (i = 0; i < SONIC_NUM_RRS; i++) {
+ struct sk_buff *skb = netdev_alloc_skb(dev, SONIC_RBSIZE + 2);
+ if (skb == NULL) {
+@@ -206,8 +208,6 @@ static void sonic_tx_timeout(struct net_
+ * wake the tx queue
+ * Concurrently with all of this, the SONIC is potentially writing to
+ * the status flags of the TDs.
+- * Until some mutual exclusion is added, this code will not work with SMP. However,
+- * MIPS Jazz machines and m68k Macs were all uni-processor machines.
+ */
+
+ static int sonic_send_packet(struct sk_buff *skb, struct net_device *dev)
+@@ -215,7 +215,8 @@ static int sonic_send_packet(struct sk_b
+ struct sonic_local *lp = netdev_priv(dev);
+ dma_addr_t laddr;
+ int length;
+- int entry = lp->next_tx;
++ int entry;
++ unsigned long flags;
+
+ netif_dbg(lp, tx_queued, dev, "%s: skb=%p\n", __func__, skb);
+
+@@ -237,6 +238,10 @@ static int sonic_send_packet(struct sk_b
+ return NETDEV_TX_OK;
+ }
+
++ spin_lock_irqsave(&lp->lock, flags);
++
++ entry = lp->next_tx;
++
+ sonic_tda_put(dev, entry, SONIC_TD_STATUS, 0); /* clear status */
+ sonic_tda_put(dev, entry, SONIC_TD_FRAG_COUNT, 1); /* single fragment */
+ sonic_tda_put(dev, entry, SONIC_TD_PKTSIZE, length); /* length of packet */
+@@ -246,10 +251,6 @@ static int sonic_send_packet(struct sk_b
+ sonic_tda_put(dev, entry, SONIC_TD_LINK,
+ sonic_tda_get(dev, entry, SONIC_TD_LINK) | SONIC_EOL);
+
+- /*
+- * Must set tx_skb[entry] only after clearing status, and
+- * before clearing EOL and before stopping queue
+- */
+ wmb();
+ lp->tx_len[entry] = length;
+ lp->tx_laddr[entry] = laddr;
+@@ -272,6 +273,8 @@ static int sonic_send_packet(struct sk_b
+
+ SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP);
+
++ spin_unlock_irqrestore(&lp->lock, flags);
++
+ return NETDEV_TX_OK;
+ }
+
+@@ -284,9 +287,21 @@ static irqreturn_t sonic_interrupt(int i
+ struct net_device *dev = dev_id;
+ struct sonic_local *lp = netdev_priv(dev);
+ int status;
++ unsigned long flags;
++
++ /* The lock has two purposes. Firstly, it synchronizes sonic_interrupt()
++ * with sonic_send_packet() so that the two functions can share state.
++ * Secondly, it makes sonic_interrupt() re-entrant, as that is required
++ * by macsonic which must use two IRQs with different priority levels.
++ */
++ spin_lock_irqsave(&lp->lock, flags);
++
++ status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT;
++ if (!status) {
++ spin_unlock_irqrestore(&lp->lock, flags);
+
+- if (!(status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT))
+ return IRQ_NONE;
++ }
+
+ do {
+ if (status & SONIC_INT_PKTRX) {
+@@ -300,11 +315,12 @@ static irqreturn_t sonic_interrupt(int i
+ int td_status;
+ int freed_some = 0;
+
+- /* At this point, cur_tx is the index of a TD that is one of:
+- * unallocated/freed (status set & tx_skb[entry] clear)
+- * allocated and sent (status set & tx_skb[entry] set )
+- * allocated and not yet sent (status clear & tx_skb[entry] set )
+- * still being allocated by sonic_send_packet (status clear & tx_skb[entry] clear)
++ /* The state of a Transmit Descriptor may be inferred
++ * from { tx_skb[entry], td_status } as follows.
++ * { clear, clear } => the TD has never been used
++ * { set, clear } => the TD was handed to SONIC
++ * { set, set } => the TD was handed back
++ * { clear, set } => the TD is available for re-use
+ */
+
+ netif_dbg(lp, intr, dev, "%s: tx done\n", __func__);
+@@ -406,7 +422,12 @@ static irqreturn_t sonic_interrupt(int i
+ /* load CAM done */
+ if (status & SONIC_INT_LCD)
+ SONIC_WRITE(SONIC_ISR, SONIC_INT_LCD); /* clear the interrupt */
+- } while((status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT));
++
++ status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT;
++ } while (status);
++
++ spin_unlock_irqrestore(&lp->lock, flags);
++
+ return IRQ_HANDLED;
+ }
+
+--- a/drivers/net/ethernet/natsemi/sonic.h
++++ b/drivers/net/ethernet/natsemi/sonic.h
+@@ -322,6 +322,7 @@ struct sonic_local {
+ int msg_enable;
+ struct device *device; /* generic device */
+ struct net_device_stats stats;
++ spinlock_t lock;
+ };
+
+ #define TX_TIMEOUT (3 * HZ)
--- /dev/null
+From eaabfd19b2c787bbe88dc32424b9a43d67293422 Mon Sep 17 00:00:00 2001
+From: Finn Thain <fthain@telegraphics.com.au>
+Date: Thu, 23 Jan 2020 09:07:26 +1100
+Subject: net/sonic: Avoid needless receive descriptor EOL flag updates
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+commit eaabfd19b2c787bbe88dc32424b9a43d67293422 upstream.
+
+The while loop in sonic_rx() traverses the rx descriptor ring. It stops
+when it reaches a descriptor that the SONIC has not used. Each iteration
+advances the EOL flag so the SONIC can keep using more descriptors.
+Therefore, the while loop has no definite termination condition.
+
+The algorithm described in the National Semiconductor literature is quite
+different. It consumes descriptors up to the one with its EOL flag set
+(which will also have its "in use" flag set). All freed descriptors are
+then returned to the ring at once, by adjusting the EOL flags (and link
+pointers).
+
+Adopt the algorithm from datasheet as it's simpler, terminates quickly
+and avoids a lot of pointless descriptor EOL flag changes.
+
+Fixes: efcce839360f ("[PATCH] macsonic/jazzsonic network drivers update")
+Tested-by: Stan Johnson <userm57@yahoo.com>
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/ethernet/natsemi/sonic.c | 21 +++++++++++++++------
+ 1 file changed, 15 insertions(+), 6 deletions(-)
+
+--- a/drivers/net/ethernet/natsemi/sonic.c
++++ b/drivers/net/ethernet/natsemi/sonic.c
+@@ -436,6 +436,7 @@ static void sonic_rx(struct net_device *
+ struct sonic_local *lp = netdev_priv(dev);
+ int status;
+ int entry = lp->cur_rx;
++ int prev_entry = lp->eol_rx;
+
+ while (sonic_rda_get(dev, entry, SONIC_RD_IN_USE) == 0) {
+ struct sk_buff *used_skb;
+@@ -516,13 +517,21 @@ static void sonic_rx(struct net_device *
+ /*
+ * give back the descriptor
+ */
+- sonic_rda_put(dev, entry, SONIC_RD_LINK,
+- sonic_rda_get(dev, entry, SONIC_RD_LINK) | SONIC_EOL);
+ sonic_rda_put(dev, entry, SONIC_RD_IN_USE, 1);
+- sonic_rda_put(dev, lp->eol_rx, SONIC_RD_LINK,
+- sonic_rda_get(dev, lp->eol_rx, SONIC_RD_LINK) & ~SONIC_EOL);
+- lp->eol_rx = entry;
+- lp->cur_rx = entry = (entry + 1) & SONIC_RDS_MASK;
++
++ prev_entry = entry;
++ entry = (entry + 1) & SONIC_RDS_MASK;
++ }
++
++ lp->cur_rx = entry;
++
++ if (prev_entry != lp->eol_rx) {
++ /* Advance the EOL flag to put descriptors back into service */
++ sonic_rda_put(dev, prev_entry, SONIC_RD_LINK, SONIC_EOL |
++ sonic_rda_get(dev, prev_entry, SONIC_RD_LINK));
++ sonic_rda_put(dev, lp->eol_rx, SONIC_RD_LINK, ~SONIC_EOL &
++ sonic_rda_get(dev, lp->eol_rx, SONIC_RD_LINK));
++ lp->eol_rx = prev_entry;
+ }
+ /*
+ * If any worth-while packets have been received, netif_rx()
--- /dev/null
+From 5fedabf5a70be26b19d7520f09f12a62274317c6 Mon Sep 17 00:00:00 2001
+From: Finn Thain <fthain@telegraphics.com.au>
+Date: Thu, 23 Jan 2020 09:07:26 +1100
+Subject: net/sonic: Clear interrupt flags immediately
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+commit 5fedabf5a70be26b19d7520f09f12a62274317c6 upstream.
+
+The chip can change a packet's descriptor status flags at any time.
+However, an active interrupt flag gets cleared rather late. This
+allows a race condition that could theoretically lose an interrupt.
+Fix this by clearing asserted interrupt flags immediately.
+
+Fixes: efcce839360f ("[PATCH] macsonic/jazzsonic network drivers update")
+Tested-by: Stan Johnson <userm57@yahoo.com>
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/ethernet/natsemi/sonic.c | 28 ++++++----------------------
+ 1 file changed, 6 insertions(+), 22 deletions(-)
+
+--- a/drivers/net/ethernet/natsemi/sonic.c
++++ b/drivers/net/ethernet/natsemi/sonic.c
+@@ -304,10 +304,11 @@ static irqreturn_t sonic_interrupt(int i
+ }
+
+ do {
++ SONIC_WRITE(SONIC_ISR, status); /* clear the interrupt(s) */
++
+ if (status & SONIC_INT_PKTRX) {
+ netif_dbg(lp, intr, dev, "%s: packet rx\n", __func__);
+ sonic_rx(dev); /* got packet(s) */
+- SONIC_WRITE(SONIC_ISR, SONIC_INT_PKTRX); /* clear the interrupt */
+ }
+
+ if (status & SONIC_INT_TXDN) {
+@@ -362,7 +363,6 @@ static irqreturn_t sonic_interrupt(int i
+ if (freed_some || lp->tx_skb[entry] == NULL)
+ netif_wake_queue(dev); /* The ring is no longer full */
+ lp->cur_tx = entry;
+- SONIC_WRITE(SONIC_ISR, SONIC_INT_TXDN); /* clear the interrupt */
+ }
+
+ /*
+@@ -372,42 +372,31 @@ static irqreturn_t sonic_interrupt(int i
+ netif_dbg(lp, rx_err, dev, "%s: rx fifo overrun\n",
+ __func__);
+ lp->stats.rx_fifo_errors++;
+- SONIC_WRITE(SONIC_ISR, SONIC_INT_RFO); /* clear the interrupt */
+ }
+ if (status & SONIC_INT_RDE) {
+ netif_dbg(lp, rx_err, dev, "%s: rx descriptors exhausted\n",
+ __func__);
+ lp->stats.rx_dropped++;
+- SONIC_WRITE(SONIC_ISR, SONIC_INT_RDE); /* clear the interrupt */
+ }
+ if (status & SONIC_INT_RBAE) {
+ netif_dbg(lp, rx_err, dev, "%s: rx buffer area exceeded\n",
+ __func__);
+ lp->stats.rx_dropped++;
+- SONIC_WRITE(SONIC_ISR, SONIC_INT_RBAE); /* clear the interrupt */
+ }
+
+ /* counter overruns; all counters are 16bit wide */
+- if (status & SONIC_INT_FAE) {
++ if (status & SONIC_INT_FAE)
+ lp->stats.rx_frame_errors += 65536;
+- SONIC_WRITE(SONIC_ISR, SONIC_INT_FAE); /* clear the interrupt */
+- }
+- if (status & SONIC_INT_CRC) {
++ if (status & SONIC_INT_CRC)
+ lp->stats.rx_crc_errors += 65536;
+- SONIC_WRITE(SONIC_ISR, SONIC_INT_CRC); /* clear the interrupt */
+- }
+- if (status & SONIC_INT_MP) {
++ if (status & SONIC_INT_MP)
+ lp->stats.rx_missed_errors += 65536;
+- SONIC_WRITE(SONIC_ISR, SONIC_INT_MP); /* clear the interrupt */
+- }
+
+ /* transmit error */
+- if (status & SONIC_INT_TXER) {
++ if (status & SONIC_INT_TXER)
+ if (SONIC_READ(SONIC_TCR) & SONIC_TCR_FU)
+ netif_dbg(lp, tx_err, dev, "%s: tx fifo underrun\n",
+ __func__);
+- SONIC_WRITE(SONIC_ISR, SONIC_INT_TXER); /* clear the interrupt */
+- }
+
+ /* bus retry */
+ if (status & SONIC_INT_BR) {
+@@ -416,13 +405,8 @@ static irqreturn_t sonic_interrupt(int i
+ /* ... to help debug DMA problems causing endless interrupts. */
+ /* Bounce the eth interface to turn on the interrupt again. */
+ SONIC_WRITE(SONIC_IMR, 0);
+- SONIC_WRITE(SONIC_ISR, SONIC_INT_BR); /* clear the interrupt */
+ }
+
+- /* load CAM done */
+- if (status & SONIC_INT_LCD)
+- SONIC_WRITE(SONIC_ISR, SONIC_INT_LCD); /* clear the interrupt */
+-
+ status = SONIC_READ(SONIC_ISR) & SONIC_IMR_DEFAULT;
+ } while (status);
+
--- /dev/null
+From 772f66421d5aa0b9f256056f513bbc38ac132271 Mon Sep 17 00:00:00 2001
+From: Finn Thain <fthain@telegraphics.com.au>
+Date: Thu, 23 Jan 2020 09:07:26 +1100
+Subject: net/sonic: Fix CAM initialization
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+commit 772f66421d5aa0b9f256056f513bbc38ac132271 upstream.
+
+Section 4.3.1 of the datasheet says,
+
+ This bit [TXP] must not be set if a Load CAM operation is in
+ progress (LCAM is set). The SONIC will lock up if both bits are
+ set simultaneously.
+
+Testing has shown that the driver sometimes attempts to set LCAM
+while TXP is set. Avoid this by waiting for command completion
+before and after giving the LCAM command.
+
+After issuing the Load CAM command, poll for !SONIC_CR_LCAM rather than
+SONIC_INT_LCD, because the SONIC_CR_TXP bit can't be used until
+!SONIC_CR_LCAM.
+
+When in reset mode, take the opportunity to reset the CAM Enable
+register.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Tested-by: Stan Johnson <userm57@yahoo.com>
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/ethernet/natsemi/sonic.c | 21 ++++++++++++---------
+ 1 file changed, 12 insertions(+), 9 deletions(-)
+
+--- a/drivers/net/ethernet/natsemi/sonic.c
++++ b/drivers/net/ethernet/natsemi/sonic.c
+@@ -634,6 +634,8 @@ static void sonic_multicast_list(struct
+ (netdev_mc_count(dev) > 15)) {
+ rcr |= SONIC_RCR_AMC;
+ } else {
++ unsigned long flags;
++
+ netif_dbg(lp, ifup, dev, "%s: mc_count %d\n", __func__,
+ netdev_mc_count(dev));
+ sonic_set_cam_enable(dev, 1); /* always enable our own address */
+@@ -647,9 +649,14 @@ static void sonic_multicast_list(struct
+ i++;
+ }
+ SONIC_WRITE(SONIC_CDC, 16);
+- /* issue Load CAM command */
+ SONIC_WRITE(SONIC_CDP, lp->cda_laddr & 0xffff);
++
++ /* LCAM and TXP commands can't be used simultaneously */
++ spin_lock_irqsave(&lp->lock, flags);
++ sonic_quiesce(dev, SONIC_CR_TXP);
+ SONIC_WRITE(SONIC_CMD, SONIC_CR_LCAM);
++ sonic_quiesce(dev, SONIC_CR_LCAM);
++ spin_unlock_irqrestore(&lp->lock, flags);
+ }
+ }
+
+@@ -675,6 +682,9 @@ static int sonic_init(struct net_device
+ SONIC_WRITE(SONIC_ISR, 0x7fff);
+ SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
+
++ /* While in reset mode, clear CAM Enable register */
++ SONIC_WRITE(SONIC_CE, 0);
++
+ /*
+ * clear software reset flag, disable receiver, clear and
+ * enable interrupts, then completely initialize the SONIC
+@@ -785,14 +795,7 @@ static int sonic_init(struct net_device
+ * load the CAM
+ */
+ SONIC_WRITE(SONIC_CMD, SONIC_CR_LCAM);
+-
+- i = 0;
+- while (i++ < 100) {
+- if (SONIC_READ(SONIC_ISR) & SONIC_INT_LCD)
+- break;
+- }
+- netif_dbg(lp, ifup, dev, "%s: CMD=%x, ISR=%x, i=%d\n", __func__,
+- SONIC_READ(SONIC_CMD), SONIC_READ(SONIC_ISR), i);
++ sonic_quiesce(dev, SONIC_CR_LCAM);
+
+ /*
+ * enable receiver, disable loopback
--- /dev/null
+From 27e0c31c5f27c1d1a1d9d135c123069f60dcf97b Mon Sep 17 00:00:00 2001
+From: Finn Thain <fthain@telegraphics.com.au>
+Date: Thu, 23 Jan 2020 09:07:26 +1100
+Subject: net/sonic: Fix command register usage
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+commit 27e0c31c5f27c1d1a1d9d135c123069f60dcf97b upstream.
+
+There are several issues relating to command register usage during
+chip initialization.
+
+Firstly, the SONIC sometimes comes out of software reset with the
+Start Timer bit set. This gets logged as,
+
+ macsonic macsonic eth0: sonic_init: status=24, i=101
+
+Avoid this by giving the Stop Timer command earlier than later.
+
+Secondly, the loop that waits for the Read RRA command to complete has
+the break condition inverted. That's why the for loop iterates until
+its termination condition. Call the helper for this instead.
+
+Finally, give the Receiver Enable command after clearing interrupts,
+not before, to avoid the possibility of losing an interrupt.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Tested-by: Stan Johnson <userm57@yahoo.com>
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/ethernet/natsemi/sonic.c | 18 +++---------------
+ 1 file changed, 3 insertions(+), 15 deletions(-)
+
+--- a/drivers/net/ethernet/natsemi/sonic.c
++++ b/drivers/net/ethernet/natsemi/sonic.c
+@@ -664,7 +664,6 @@ static void sonic_multicast_list(struct
+ */
+ static int sonic_init(struct net_device *dev)
+ {
+- unsigned int cmd;
+ struct sonic_local *lp = netdev_priv(dev);
+ int i;
+
+@@ -681,7 +680,7 @@ static int sonic_init(struct net_device
+ * enable interrupts, then completely initialize the SONIC
+ */
+ SONIC_WRITE(SONIC_CMD, 0);
+- SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS);
++ SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS | SONIC_CR_STP);
+ sonic_quiesce(dev, SONIC_CR_ALL);
+
+ /*
+@@ -711,14 +710,7 @@ static int sonic_init(struct net_device
+ netif_dbg(lp, ifup, dev, "%s: issuing RRRA command\n", __func__);
+
+ SONIC_WRITE(SONIC_CMD, SONIC_CR_RRRA);
+- i = 0;
+- while (i++ < 100) {
+- if (SONIC_READ(SONIC_CMD) & SONIC_CR_RRRA)
+- break;
+- }
+-
+- netif_dbg(lp, ifup, dev, "%s: status=%x, i=%d\n", __func__,
+- SONIC_READ(SONIC_CMD), i);
++ sonic_quiesce(dev, SONIC_CR_RRRA);
+
+ /*
+ * Initialize the receive descriptors so that they
+@@ -806,15 +798,11 @@ static int sonic_init(struct net_device
+ * enable receiver, disable loopback
+ * and enable all interrupts
+ */
+- SONIC_WRITE(SONIC_CMD, SONIC_CR_RXEN | SONIC_CR_STP);
+ SONIC_WRITE(SONIC_RCR, SONIC_RCR_DEFAULT);
+ SONIC_WRITE(SONIC_TCR, SONIC_TCR_DEFAULT);
+ SONIC_WRITE(SONIC_ISR, 0x7fff);
+ SONIC_WRITE(SONIC_IMR, SONIC_IMR_DEFAULT);
+-
+- cmd = SONIC_READ(SONIC_CMD);
+- if ((cmd & SONIC_CR_RXEN) == 0 || (cmd & SONIC_CR_STP) == 0)
+- printk(KERN_ERR "sonic_init: failed, status=%x\n", cmd);
++ SONIC_WRITE(SONIC_CMD, SONIC_CR_RXEN);
+
+ netif_dbg(lp, ifup, dev, "%s: new status=%x\n", __func__,
+ SONIC_READ(SONIC_CMD));
--- /dev/null
+From 427db97df1ee721c20bdc9a66db8a9e1da719855 Mon Sep 17 00:00:00 2001
+From: Finn Thain <fthain@telegraphics.com.au>
+Date: Thu, 23 Jan 2020 09:07:26 +1100
+Subject: net/sonic: Fix interface error stats collection
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+commit 427db97df1ee721c20bdc9a66db8a9e1da719855 upstream.
+
+The tx_aborted_errors statistic should count packets flagged with EXD,
+EXC, FU, or BCM bits because those bits denote an aborted transmission.
+That corresponds to the bitmask 0x0446, not 0x0642. Use macros for these
+constants to avoid mistakes. Better to leave out FIFO Underruns (FU) as
+there's a separate counter for that purpose.
+
+Don't lump all these errors in with the general tx_errors counter as
+that's used for tx timeout events.
+
+On the rx side, don't count RDE and RBAE interrupts as dropped packets.
+These interrupts don't indicate a lost packet, just a lack of resources.
+When a lack of resources results in a lost packet, this gets reported
+in the rx_missed_errors counter (along with RFO events).
+
+Don't double-count rx_frame_errors and rx_crc_errors.
+
+Don't use the general rx_errors counter for events that already have
+special counters.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Tested-by: Stan Johnson <userm57@yahoo.com>
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/ethernet/natsemi/sonic.c | 21 +++++++--------------
+ drivers/net/ethernet/natsemi/sonic.h | 1 +
+ 2 files changed, 8 insertions(+), 14 deletions(-)
+
+--- a/drivers/net/ethernet/natsemi/sonic.c
++++ b/drivers/net/ethernet/natsemi/sonic.c
+@@ -330,18 +330,19 @@ static irqreturn_t sonic_interrupt(int i
+ if ((td_status = sonic_tda_get(dev, entry, SONIC_TD_STATUS)) == 0)
+ break;
+
+- if (td_status & 0x0001) {
++ if (td_status & SONIC_TCR_PTX) {
+ lp->stats.tx_packets++;
+ lp->stats.tx_bytes += sonic_tda_get(dev, entry, SONIC_TD_PKTSIZE);
+ } else {
+- lp->stats.tx_errors++;
+- if (td_status & 0x0642)
++ if (td_status & (SONIC_TCR_EXD |
++ SONIC_TCR_EXC | SONIC_TCR_BCM))
+ lp->stats.tx_aborted_errors++;
+- if (td_status & 0x0180)
++ if (td_status &
++ (SONIC_TCR_NCRS | SONIC_TCR_CRLS))
+ lp->stats.tx_carrier_errors++;
+- if (td_status & 0x0020)
++ if (td_status & SONIC_TCR_OWC)
+ lp->stats.tx_window_errors++;
+- if (td_status & 0x0004)
++ if (td_status & SONIC_TCR_FU)
+ lp->stats.tx_fifo_errors++;
+ }
+
+@@ -371,17 +372,14 @@ static irqreturn_t sonic_interrupt(int i
+ if (status & SONIC_INT_RFO) {
+ netif_dbg(lp, rx_err, dev, "%s: rx fifo overrun\n",
+ __func__);
+- lp->stats.rx_fifo_errors++;
+ }
+ if (status & SONIC_INT_RDE) {
+ netif_dbg(lp, rx_err, dev, "%s: rx descriptors exhausted\n",
+ __func__);
+- lp->stats.rx_dropped++;
+ }
+ if (status & SONIC_INT_RBAE) {
+ netif_dbg(lp, rx_err, dev, "%s: rx buffer area exceeded\n",
+ __func__);
+- lp->stats.rx_dropped++;
+ }
+
+ /* counter overruns; all counters are 16bit wide */
+@@ -473,11 +471,6 @@ static void sonic_rx(struct net_device *
+ sonic_rra_put(dev, entry, SONIC_RR_BUFADR_H, bufadr_h);
+ } else {
+ /* This should only happen, if we enable accepting broken packets. */
+- lp->stats.rx_errors++;
+- if (status & SONIC_RCR_FAER)
+- lp->stats.rx_frame_errors++;
+- if (status & SONIC_RCR_CRCR)
+- lp->stats.rx_crc_errors++;
+ }
+ if (status & SONIC_RCR_LPKT) {
+ /*
+--- a/drivers/net/ethernet/natsemi/sonic.h
++++ b/drivers/net/ethernet/natsemi/sonic.h
+@@ -175,6 +175,7 @@
+ #define SONIC_TCR_NCRS 0x0100
+ #define SONIC_TCR_CRLS 0x0080
+ #define SONIC_TCR_EXC 0x0040
++#define SONIC_TCR_OWC 0x0020
+ #define SONIC_TCR_PMB 0x0008
+ #define SONIC_TCR_FU 0x0004
+ #define SONIC_TCR_BCM 0x0002
--- /dev/null
+From 9e311820f67e740f4fb8dcb82b4c4b5b05bdd1a5 Mon Sep 17 00:00:00 2001
+From: Finn Thain <fthain@telegraphics.com.au>
+Date: Thu, 23 Jan 2020 09:07:26 +1100
+Subject: net/sonic: Fix receive buffer handling
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+commit 9e311820f67e740f4fb8dcb82b4c4b5b05bdd1a5 upstream.
+
+The SONIC can sometimes advance its rx buffer pointer (RRP register)
+without advancing its rx descriptor pointer (CRDA register). As a result
+the index of the current rx descriptor may not equal that of the current
+rx buffer. The driver mistakenly assumes that they are always equal.
+This assumption leads to incorrect packet lengths and possible packet
+duplication. Avoid this by calling a new function to locate the buffer
+corresponding to a given descriptor.
+
+Fixes: efcce839360f ("[PATCH] macsonic/jazzsonic network drivers update")
+Tested-by: Stan Johnson <userm57@yahoo.com>
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/ethernet/natsemi/sonic.c | 35 ++++++++++++++++++++++++++++++-----
+ drivers/net/ethernet/natsemi/sonic.h | 5 +++--
+ 2 files changed, 33 insertions(+), 7 deletions(-)
+
+--- a/drivers/net/ethernet/natsemi/sonic.c
++++ b/drivers/net/ethernet/natsemi/sonic.c
+@@ -413,6 +413,21 @@ static irqreturn_t sonic_interrupt(int i
+ return IRQ_HANDLED;
+ }
+
++/* Return the array index corresponding to a given Receive Buffer pointer. */
++static int index_from_addr(struct sonic_local *lp, dma_addr_t addr,
++ unsigned int last)
++{
++ unsigned int i = last;
++
++ do {
++ i = (i + 1) & SONIC_RRS_MASK;
++ if (addr == lp->rx_laddr[i])
++ return i;
++ } while (i != last);
++
++ return -ENOENT;
++}
++
+ /*
+ * We have a good packet(s), pass it/them up the network stack.
+ */
+@@ -432,6 +447,16 @@ static void sonic_rx(struct net_device *
+
+ status = sonic_rda_get(dev, entry, SONIC_RD_STATUS);
+ if (status & SONIC_RCR_PRX) {
++ u32 addr = (sonic_rda_get(dev, entry,
++ SONIC_RD_PKTPTR_H) << 16) |
++ sonic_rda_get(dev, entry, SONIC_RD_PKTPTR_L);
++ int i = index_from_addr(lp, addr, entry);
++
++ if (i < 0) {
++ WARN_ONCE(1, "failed to find buffer!\n");
++ break;
++ }
++
+ /* Malloc up new buffer. */
+ new_skb = netdev_alloc_skb(dev, SONIC_RBSIZE + 2);
+ if (new_skb == NULL) {
+@@ -453,7 +478,7 @@ static void sonic_rx(struct net_device *
+
+ /* now we have a new skb to replace it, pass the used one up the stack */
+ dma_unmap_single(lp->device, lp->rx_laddr[entry], SONIC_RBSIZE, DMA_FROM_DEVICE);
+- used_skb = lp->rx_skb[entry];
++ used_skb = lp->rx_skb[i];
+ pkt_len = sonic_rda_get(dev, entry, SONIC_RD_PKTLEN);
+ skb_trim(used_skb, pkt_len);
+ used_skb->protocol = eth_type_trans(used_skb, dev);
+@@ -462,13 +487,13 @@ static void sonic_rx(struct net_device *
+ lp->stats.rx_bytes += pkt_len;
+
+ /* and insert the new skb */
+- lp->rx_laddr[entry] = new_laddr;
+- lp->rx_skb[entry] = new_skb;
++ lp->rx_laddr[i] = new_laddr;
++ lp->rx_skb[i] = new_skb;
+
+ bufadr_l = (unsigned long)new_laddr & 0xffff;
+ bufadr_h = (unsigned long)new_laddr >> 16;
+- sonic_rra_put(dev, entry, SONIC_RR_BUFADR_L, bufadr_l);
+- sonic_rra_put(dev, entry, SONIC_RR_BUFADR_H, bufadr_h);
++ sonic_rra_put(dev, i, SONIC_RR_BUFADR_L, bufadr_l);
++ sonic_rra_put(dev, i, SONIC_RR_BUFADR_H, bufadr_h);
+ } else {
+ /* This should only happen, if we enable accepting broken packets. */
+ }
+--- a/drivers/net/ethernet/natsemi/sonic.h
++++ b/drivers/net/ethernet/natsemi/sonic.h
+@@ -275,8 +275,9 @@
+ #define SONIC_NUM_RDS SONIC_NUM_RRS /* number of receive descriptors */
+ #define SONIC_NUM_TDS 16 /* number of transmit descriptors */
+
+-#define SONIC_RDS_MASK (SONIC_NUM_RDS-1)
+-#define SONIC_TDS_MASK (SONIC_NUM_TDS-1)
++#define SONIC_RRS_MASK (SONIC_NUM_RRS - 1)
++#define SONIC_RDS_MASK (SONIC_NUM_RDS - 1)
++#define SONIC_TDS_MASK (SONIC_NUM_TDS - 1)
+
+ #define SONIC_RBSIZE 1520 /* size of one resource buffer */
+
--- /dev/null
+From 89ba879e95582d3bba55081e45b5409e883312ca Mon Sep 17 00:00:00 2001
+From: Finn Thain <fthain@telegraphics.com.au>
+Date: Thu, 23 Jan 2020 09:07:26 +1100
+Subject: net/sonic: Fix receive buffer replenishment
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+commit 89ba879e95582d3bba55081e45b5409e883312ca upstream.
+
+As soon as the driver is finished with a receive buffer it allocs a new
+one and overwrites the corresponding RRA entry with a new buffer pointer.
+
+Problem is, the buffer pointer is split across two word-sized registers.
+It can't be updated in one atomic store. So this operation races with the
+chip while it stores received packets and advances its RRP register.
+This could result in memory corruption by a DMA write.
+
+Avoid this problem by adding buffers only at the location given by the
+RWP register, in accordance with the National Semiconductor datasheet.
+
+Re-factor this code into separate functions to calculate a RRA pointer
+and to update the RWP.
+
+Fixes: efcce839360f ("[PATCH] macsonic/jazzsonic network drivers update")
+Tested-by: Stan Johnson <userm57@yahoo.com>
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/ethernet/natsemi/sonic.c | 150 ++++++++++++++++++++---------------
+ drivers/net/ethernet/natsemi/sonic.h | 18 +++-
+ 2 files changed, 105 insertions(+), 63 deletions(-)
+
+--- a/drivers/net/ethernet/natsemi/sonic.c
++++ b/drivers/net/ethernet/natsemi/sonic.c
+@@ -428,6 +428,59 @@ static int index_from_addr(struct sonic_
+ return -ENOENT;
+ }
+
++/* Allocate and map a new skb to be used as a receive buffer. */
++static bool sonic_alloc_rb(struct net_device *dev, struct sonic_local *lp,
++ struct sk_buff **new_skb, dma_addr_t *new_addr)
++{
++ *new_skb = netdev_alloc_skb(dev, SONIC_RBSIZE + 2);
++ if (!*new_skb)
++ return false;
++
++ if (SONIC_BUS_SCALE(lp->dma_bitmode) == 2)
++ skb_reserve(*new_skb, 2);
++
++ *new_addr = dma_map_single(lp->device, skb_put(*new_skb, SONIC_RBSIZE),
++ SONIC_RBSIZE, DMA_FROM_DEVICE);
++ if (!*new_addr) {
++ dev_kfree_skb(*new_skb);
++ *new_skb = NULL;
++ return false;
++ }
++
++ return true;
++}
++
++/* Place a new receive resource in the Receive Resource Area and update RWP. */
++static void sonic_update_rra(struct net_device *dev, struct sonic_local *lp,
++ dma_addr_t old_addr, dma_addr_t new_addr)
++{
++ unsigned int entry = sonic_rr_entry(dev, SONIC_READ(SONIC_RWP));
++ unsigned int end = sonic_rr_entry(dev, SONIC_READ(SONIC_RRP));
++ u32 buf;
++
++ /* The resources in the range [RRP, RWP) belong to the SONIC. This loop
++ * scans the other resources in the RRA, those in the range [RWP, RRP).
++ */
++ do {
++ buf = (sonic_rra_get(dev, entry, SONIC_RR_BUFADR_H) << 16) |
++ sonic_rra_get(dev, entry, SONIC_RR_BUFADR_L);
++
++ if (buf == old_addr)
++ break;
++
++ entry = (entry + 1) & SONIC_RRS_MASK;
++ } while (entry != end);
++
++ WARN_ONCE(buf != old_addr, "failed to find resource!\n");
++
++ sonic_rra_put(dev, entry, SONIC_RR_BUFADR_H, new_addr >> 16);
++ sonic_rra_put(dev, entry, SONIC_RR_BUFADR_L, new_addr & 0xffff);
++
++ entry = (entry + 1) & SONIC_RRS_MASK;
++
++ SONIC_WRITE(SONIC_RWP, sonic_rr_addr(dev, entry));
++}
++
+ /*
+ * We have a good packet(s), pass it/them up the network stack.
+ */
+@@ -436,18 +489,15 @@ static void sonic_rx(struct net_device *
+ struct sonic_local *lp = netdev_priv(dev);
+ int entry = lp->cur_rx;
+ int prev_entry = lp->eol_rx;
++ bool rbe = false;
+
+ while (sonic_rda_get(dev, entry, SONIC_RD_IN_USE) == 0) {
+- struct sk_buff *used_skb;
+- struct sk_buff *new_skb;
+- dma_addr_t new_laddr;
+- u16 bufadr_l;
+- u16 bufadr_h;
+- int pkt_len;
+ u16 status = sonic_rda_get(dev, entry, SONIC_RD_STATUS);
+
+ /* If the RD has LPKT set, the chip has finished with the RB */
+ if ((status & SONIC_RCR_PRX) && (status & SONIC_RCR_LPKT)) {
++ struct sk_buff *new_skb;
++ dma_addr_t new_laddr;
+ u32 addr = (sonic_rda_get(dev, entry,
+ SONIC_RD_PKTPTR_H) << 16) |
+ sonic_rda_get(dev, entry, SONIC_RD_PKTPTR_L);
+@@ -458,55 +508,35 @@ static void sonic_rx(struct net_device *
+ break;
+ }
+
+- /* Malloc up new buffer. */
+- new_skb = netdev_alloc_skb(dev, SONIC_RBSIZE + 2);
+- if (new_skb == NULL) {
++ if (sonic_alloc_rb(dev, lp, &new_skb, &new_laddr)) {
++ struct sk_buff *used_skb = lp->rx_skb[i];
++ int pkt_len;
++
++ /* Pass the used buffer up the stack */
++ dma_unmap_single(lp->device, addr, SONIC_RBSIZE,
++ DMA_FROM_DEVICE);
++
++ pkt_len = sonic_rda_get(dev, entry,
++ SONIC_RD_PKTLEN);
++ skb_trim(used_skb, pkt_len);
++ used_skb->protocol = eth_type_trans(used_skb,
++ dev);
++ netif_rx(used_skb);
++ lp->stats.rx_packets++;
++ lp->stats.rx_bytes += pkt_len;
++
++ lp->rx_skb[i] = new_skb;
++ lp->rx_laddr[i] = new_laddr;
++ } else {
++ /* Failed to obtain a new buffer so re-use it */
++ new_laddr = addr;
+ lp->stats.rx_dropped++;
+- break;
+ }
+- /* provide 16 byte IP header alignment unless DMA requires otherwise */
+- if(SONIC_BUS_SCALE(lp->dma_bitmode) == 2)
+- skb_reserve(new_skb, 2);
+-
+- new_laddr = dma_map_single(lp->device, skb_put(new_skb, SONIC_RBSIZE),
+- SONIC_RBSIZE, DMA_FROM_DEVICE);
+- if (!new_laddr) {
+- dev_kfree_skb(new_skb);
+- printk(KERN_ERR "%s: Failed to map rx buffer, dropping packet.\n", dev->name);
+- lp->stats.rx_dropped++;
+- break;
+- }
+-
+- /* now we have a new skb to replace it, pass the used one up the stack */
+- dma_unmap_single(lp->device, lp->rx_laddr[entry], SONIC_RBSIZE, DMA_FROM_DEVICE);
+- used_skb = lp->rx_skb[i];
+- pkt_len = sonic_rda_get(dev, entry, SONIC_RD_PKTLEN);
+- skb_trim(used_skb, pkt_len);
+- used_skb->protocol = eth_type_trans(used_skb, dev);
+- netif_rx(used_skb);
+- lp->stats.rx_packets++;
+- lp->stats.rx_bytes += pkt_len;
+-
+- /* and insert the new skb */
+- lp->rx_laddr[i] = new_laddr;
+- lp->rx_skb[i] = new_skb;
+-
+- bufadr_l = (unsigned long)new_laddr & 0xffff;
+- bufadr_h = (unsigned long)new_laddr >> 16;
+- sonic_rra_put(dev, i, SONIC_RR_BUFADR_L, bufadr_l);
+- sonic_rra_put(dev, i, SONIC_RR_BUFADR_H, bufadr_h);
+- /*
+- * this was the last packet out of the current receive buffer
+- * give the buffer back to the SONIC
++ /* If RBE is already asserted when RWP advances then
++ * it's safe to clear RBE after processing this packet.
+ */
+- lp->cur_rwp += SIZEOF_SONIC_RR * SONIC_BUS_SCALE(lp->dma_bitmode);
+- if (lp->cur_rwp >= lp->rra_end) lp->cur_rwp = lp->rra_laddr & 0xffff;
+- SONIC_WRITE(SONIC_RWP, lp->cur_rwp);
+- if (SONIC_READ(SONIC_ISR) & SONIC_INT_RBE) {
+- netif_dbg(lp, rx_err, dev, "%s: rx buffer exhausted\n",
+- __func__);
+- SONIC_WRITE(SONIC_ISR, SONIC_INT_RBE); /* clear the flag */
+- }
++ rbe = rbe || SONIC_READ(SONIC_ISR) & SONIC_INT_RBE;
++ sonic_update_rra(dev, lp, addr, new_laddr);
+ }
+ /*
+ * give back the descriptor
+@@ -528,6 +558,9 @@ static void sonic_rx(struct net_device *
+ sonic_rda_get(dev, lp->eol_rx, SONIC_RD_LINK));
+ lp->eol_rx = prev_entry;
+ }
++
++ if (rbe)
++ SONIC_WRITE(SONIC_ISR, SONIC_INT_RBE);
+ /*
+ * If any worth-while packets have been received, netif_rx()
+ * has done a mark_bh(NET_BH) for us and will work on them
+@@ -642,15 +675,10 @@ static int sonic_init(struct net_device
+ }
+
+ /* initialize all RRA registers */
+- lp->rra_end = (lp->rra_laddr + SONIC_NUM_RRS * SIZEOF_SONIC_RR *
+- SONIC_BUS_SCALE(lp->dma_bitmode)) & 0xffff;
+- lp->cur_rwp = (lp->rra_laddr + (SONIC_NUM_RRS - 1) * SIZEOF_SONIC_RR *
+- SONIC_BUS_SCALE(lp->dma_bitmode)) & 0xffff;
+-
+- SONIC_WRITE(SONIC_RSA, lp->rra_laddr & 0xffff);
+- SONIC_WRITE(SONIC_REA, lp->rra_end);
+- SONIC_WRITE(SONIC_RRP, lp->rra_laddr & 0xffff);
+- SONIC_WRITE(SONIC_RWP, lp->cur_rwp);
++ SONIC_WRITE(SONIC_RSA, sonic_rr_addr(dev, 0));
++ SONIC_WRITE(SONIC_REA, sonic_rr_addr(dev, SONIC_NUM_RRS));
++ SONIC_WRITE(SONIC_RRP, sonic_rr_addr(dev, 0));
++ SONIC_WRITE(SONIC_RWP, sonic_rr_addr(dev, SONIC_NUM_RRS - 1));
+ SONIC_WRITE(SONIC_URRA, lp->rra_laddr >> 16);
+ SONIC_WRITE(SONIC_EOBC, (SONIC_RBSIZE >> 1) - (lp->dma_bitmode ? 2 : 1));
+
+--- a/drivers/net/ethernet/natsemi/sonic.h
++++ b/drivers/net/ethernet/natsemi/sonic.h
+@@ -314,8 +314,6 @@ struct sonic_local {
+ u32 rda_laddr; /* logical DMA address of RDA */
+ dma_addr_t rx_laddr[SONIC_NUM_RRS]; /* logical DMA addresses of rx skbuffs */
+ dma_addr_t tx_laddr[SONIC_NUM_TDS]; /* logical DMA addresses of tx skbuffs */
+- unsigned int rra_end;
+- unsigned int cur_rwp;
+ unsigned int cur_rx;
+ unsigned int cur_tx; /* first unacked transmit packet */
+ unsigned int eol_rx;
+@@ -450,6 +448,22 @@ static inline __u16 sonic_rra_get(struct
+ (entry * SIZEOF_SONIC_RR) + offset);
+ }
+
++static inline u16 sonic_rr_addr(struct net_device *dev, int entry)
++{
++ struct sonic_local *lp = netdev_priv(dev);
++
++ return lp->rra_laddr +
++ entry * SIZEOF_SONIC_RR * SONIC_BUS_SCALE(lp->dma_bitmode);
++}
++
++static inline u16 sonic_rr_entry(struct net_device *dev, u16 addr)
++{
++ struct sonic_local *lp = netdev_priv(dev);
++
++ return (addr - (u16)lp->rra_laddr) / (SIZEOF_SONIC_RR *
++ SONIC_BUS_SCALE(lp->dma_bitmode));
++}
++
+ static const char version[] =
+ "sonic.c:v0.92 20.9.98 tsbogend@alpha.franken.de\n";
+
--- /dev/null
+From 94b166349503957079ef5e7d6f667f157aea014a Mon Sep 17 00:00:00 2001
+From: Finn Thain <fthain@telegraphics.com.au>
+Date: Thu, 23 Jan 2020 09:07:26 +1100
+Subject: net/sonic: Improve receive descriptor status flag check
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+commit 94b166349503957079ef5e7d6f667f157aea014a upstream.
+
+After sonic_tx_timeout() calls sonic_init(), it can happen that
+sonic_rx() will subsequently encounter a receive descriptor with no
+flags set. Remove the comment that says that this can't happen.
+
+When giving a receive descriptor to the SONIC, clear the descriptor
+status field. That way, any rx descriptor with flags set can only be
+a newly received packet.
+
+Don't process a descriptor without the LPKT bit set. The buffer is
+still in use by the SONIC.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Tested-by: Stan Johnson <userm57@yahoo.com>
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/ethernet/natsemi/sonic.c | 15 +++++----------
+ 1 file changed, 5 insertions(+), 10 deletions(-)
+
+--- a/drivers/net/ethernet/natsemi/sonic.c
++++ b/drivers/net/ethernet/natsemi/sonic.c
+@@ -434,7 +434,6 @@ static int index_from_addr(struct sonic_
+ static void sonic_rx(struct net_device *dev)
+ {
+ struct sonic_local *lp = netdev_priv(dev);
+- int status;
+ int entry = lp->cur_rx;
+ int prev_entry = lp->eol_rx;
+
+@@ -445,9 +444,10 @@ static void sonic_rx(struct net_device *
+ u16 bufadr_l;
+ u16 bufadr_h;
+ int pkt_len;
++ u16 status = sonic_rda_get(dev, entry, SONIC_RD_STATUS);
+
+- status = sonic_rda_get(dev, entry, SONIC_RD_STATUS);
+- if (status & SONIC_RCR_PRX) {
++ /* If the RD has LPKT set, the chip has finished with the RB */
++ if ((status & SONIC_RCR_PRX) && (status & SONIC_RCR_LPKT)) {
+ u32 addr = (sonic_rda_get(dev, entry,
+ SONIC_RD_PKTPTR_H) << 16) |
+ sonic_rda_get(dev, entry, SONIC_RD_PKTPTR_L);
+@@ -495,10 +495,6 @@ static void sonic_rx(struct net_device *
+ bufadr_h = (unsigned long)new_laddr >> 16;
+ sonic_rra_put(dev, i, SONIC_RR_BUFADR_L, bufadr_l);
+ sonic_rra_put(dev, i, SONIC_RR_BUFADR_H, bufadr_h);
+- } else {
+- /* This should only happen, if we enable accepting broken packets. */
+- }
+- if (status & SONIC_RCR_LPKT) {
+ /*
+ * this was the last packet out of the current receive buffer
+ * give the buffer back to the SONIC
+@@ -511,12 +507,11 @@ static void sonic_rx(struct net_device *
+ __func__);
+ SONIC_WRITE(SONIC_ISR, SONIC_INT_RBE); /* clear the flag */
+ }
+- } else
+- printk(KERN_ERR "%s: rx desc without RCR_LPKT. Shouldn't happen !?\n",
+- dev->name);
++ }
+ /*
+ * give back the descriptor
+ */
++ sonic_rda_put(dev, entry, SONIC_RD_STATUS, 0);
+ sonic_rda_put(dev, entry, SONIC_RD_IN_USE, 1);
+
+ prev_entry = entry;
--- /dev/null
+From 686f85d71d095f1d26b807e23b0f0bfd22042c45 Mon Sep 17 00:00:00 2001
+From: Finn Thain <fthain@telegraphics.com.au>
+Date: Thu, 23 Jan 2020 09:07:26 +1100
+Subject: net/sonic: Prevent tx watchdog timeout
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+commit 686f85d71d095f1d26b807e23b0f0bfd22042c45 upstream.
+
+Section 5.5.3.2 of the datasheet says,
+
+ If FIFO Underrun, Byte Count Mismatch, Excessive Collision, or
+ Excessive Deferral (if enabled) errors occur, transmission ceases.
+
+In this situation, the chip asserts a TXER interrupt rather than TXDN.
+But the handler for the TXDN is the only way that the transmit queue
+gets restarted. Hence, an aborted transmission can result in a watchdog
+timeout.
+
+This problem can be reproduced on congested link, as that can result in
+excessive transmitter collisions. Another way to reproduce this is with
+a FIFO Underrun, which may be caused by DMA latency.
+
+In event of a TXER interrupt, prevent a watchdog timeout by restarting
+transmission.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Tested-by: Stan Johnson <userm57@yahoo.com>
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/ethernet/natsemi/sonic.c | 17 +++++++++++++----
+ 1 file changed, 13 insertions(+), 4 deletions(-)
+
+--- a/drivers/net/ethernet/natsemi/sonic.c
++++ b/drivers/net/ethernet/natsemi/sonic.c
+@@ -415,10 +415,19 @@ static irqreturn_t sonic_interrupt(int i
+ lp->stats.rx_missed_errors += 65536;
+
+ /* transmit error */
+- if (status & SONIC_INT_TXER)
+- if (SONIC_READ(SONIC_TCR) & SONIC_TCR_FU)
+- netif_dbg(lp, tx_err, dev, "%s: tx fifo underrun\n",
+- __func__);
++ if (status & SONIC_INT_TXER) {
++ u16 tcr = SONIC_READ(SONIC_TCR);
++
++ netif_dbg(lp, tx_err, dev, "%s: TXER intr, TCR %04x\n",
++ __func__, tcr);
++
++ if (tcr & (SONIC_TCR_EXD | SONIC_TCR_EXC |
++ SONIC_TCR_FU | SONIC_TCR_BCM)) {
++ /* Aborted transmission. Try again. */
++ netif_stop_queue(dev);
++ SONIC_WRITE(SONIC_CMD, SONIC_CR_TXP);
++ }
++ }
+
+ /* bus retry */
+ if (status & SONIC_INT_BR) {
--- /dev/null
+From 3f4b7e6a2be982fd8820a2b54d46dd9c351db899 Mon Sep 17 00:00:00 2001
+From: Finn Thain <fthain@telegraphics.com.au>
+Date: Thu, 23 Jan 2020 09:07:26 +1100
+Subject: net/sonic: Quiesce SONIC before re-initializing descriptor memory
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+commit 3f4b7e6a2be982fd8820a2b54d46dd9c351db899 upstream.
+
+Make sure the SONIC's DMA engine is idle before altering the transmit
+and receive descriptors. Add a helper for this as it will be needed
+again.
+
+Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
+Tested-by: Stan Johnson <userm57@yahoo.com>
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/ethernet/natsemi/sonic.c | 25 +++++++++++++++++++++++++
+ drivers/net/ethernet/natsemi/sonic.h | 3 +++
+ 2 files changed, 28 insertions(+)
+
+--- a/drivers/net/ethernet/natsemi/sonic.c
++++ b/drivers/net/ethernet/natsemi/sonic.c
+@@ -116,6 +116,24 @@ static int sonic_open(struct net_device
+ return 0;
+ }
+
++/* Wait for the SONIC to become idle. */
++static void sonic_quiesce(struct net_device *dev, u16 mask)
++{
++ struct sonic_local * __maybe_unused lp = netdev_priv(dev);
++ int i;
++ u16 bits;
++
++ for (i = 0; i < 1000; ++i) {
++ bits = SONIC_READ(SONIC_CMD) & mask;
++ if (!bits)
++ return;
++ if (irqs_disabled() || in_interrupt())
++ udelay(20);
++ else
++ usleep_range(100, 200);
++ }
++ WARN_ONCE(1, "command deadline expired! 0x%04x\n", bits);
++}
+
+ /*
+ * Close the SONIC device
+@@ -132,6 +150,9 @@ static int sonic_close(struct net_device
+ /*
+ * stop the SONIC, disable interrupts
+ */
++ SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS);
++ sonic_quiesce(dev, SONIC_CR_ALL);
++
+ SONIC_WRITE(SONIC_IMR, 0);
+ SONIC_WRITE(SONIC_ISR, 0x7fff);
+ SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
+@@ -171,6 +192,9 @@ static void sonic_tx_timeout(struct net_
+ * put the Sonic into software-reset mode and
+ * disable all interrupts before releasing DMA buffers
+ */
++ SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS);
++ sonic_quiesce(dev, SONIC_CR_ALL);
++
+ SONIC_WRITE(SONIC_IMR, 0);
+ SONIC_WRITE(SONIC_ISR, 0x7fff);
+ SONIC_WRITE(SONIC_CMD, SONIC_CR_RST);
+@@ -658,6 +682,7 @@ static int sonic_init(struct net_device
+ */
+ SONIC_WRITE(SONIC_CMD, 0);
+ SONIC_WRITE(SONIC_CMD, SONIC_CR_RXDIS);
++ sonic_quiesce(dev, SONIC_CR_ALL);
+
+ /*
+ * initialize the receive resource area
+--- a/drivers/net/ethernet/natsemi/sonic.h
++++ b/drivers/net/ethernet/natsemi/sonic.h
+@@ -110,6 +110,9 @@
+ #define SONIC_CR_TXP 0x0002
+ #define SONIC_CR_HTX 0x0001
+
++#define SONIC_CR_ALL (SONIC_CR_LCAM | SONIC_CR_RRRA | \
++ SONIC_CR_RXEN | SONIC_CR_TXP)
++
+ /*
+ * SONIC data configuration bits
+ */
--- /dev/null
+From e3885f576196ddfc670b3d53e745de96ffcb49ab Mon Sep 17 00:00:00 2001
+From: Finn Thain <fthain@telegraphics.com.au>
+Date: Thu, 23 Jan 2020 09:07:26 +1100
+Subject: net/sonic: Use MMIO accessors
+
+From: Finn Thain <fthain@telegraphics.com.au>
+
+commit e3885f576196ddfc670b3d53e745de96ffcb49ab upstream.
+
+The driver accesses descriptor memory which is simultaneously accessed by
+the chip, so the compiler must not be allowed to re-order CPU accesses.
+sonic_buf_get() used 'volatile' to prevent that. sonic_buf_put() should
+have done so too but was overlooked.
+
+Fixes: efcce839360f ("[PATCH] macsonic/jazzsonic network drivers update")
+Tested-by: Stan Johnson <userm57@yahoo.com>
+Signed-off-by: Finn Thain <fthain@telegraphics.com.au>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/net/ethernet/natsemi/sonic.h | 16 ++++++++--------
+ 1 file changed, 8 insertions(+), 8 deletions(-)
+
+--- a/drivers/net/ethernet/natsemi/sonic.h
++++ b/drivers/net/ethernet/natsemi/sonic.h
+@@ -345,30 +345,30 @@ static void sonic_msg_init(struct net_de
+ as far as we can tell. */
+ /* OpenBSD calls this "SWO". I'd like to think that sonic_buf_put()
+ is a much better name. */
+-static inline void sonic_buf_put(void* base, int bitmode,
++static inline void sonic_buf_put(u16 *base, int bitmode,
+ int offset, __u16 val)
+ {
+ if (bitmode)
+ #ifdef __BIG_ENDIAN
+- ((__u16 *) base + (offset*2))[1] = val;
++ __raw_writew(val, base + (offset * 2) + 1);
+ #else
+- ((__u16 *) base + (offset*2))[0] = val;
++ __raw_writew(val, base + (offset * 2) + 0);
+ #endif
+ else
+- ((__u16 *) base)[offset] = val;
++ __raw_writew(val, base + (offset * 1) + 0);
+ }
+
+-static inline __u16 sonic_buf_get(void* base, int bitmode,
++static inline __u16 sonic_buf_get(u16 *base, int bitmode,
+ int offset)
+ {
+ if (bitmode)
+ #ifdef __BIG_ENDIAN
+- return ((volatile __u16 *) base + (offset*2))[1];
++ return __raw_readw(base + (offset * 2) + 1);
+ #else
+- return ((volatile __u16 *) base + (offset*2))[0];
++ return __raw_readw(base + (offset * 2) + 0);
+ #endif
+ else
+- return ((volatile __u16 *) base)[offset];
++ return __raw_readw(base + (offset * 1) + 0);
+ }
+
+ /* Inlines that you should actually use for reading/writing DMA buffers */
net-sk_msg-don-t-check-if-sock-is-locked-when-tearing-down-psock.patch
do_last-fetch-directory-i_mode-and-i_uid-before-it-s-too-late.patch
readdir-be-more-conservative-with-directory-entry-names.patch
+net-sonic-add-mutual-exclusion-for-accessing-shared-state.patch
+net-sonic-clear-interrupt-flags-immediately.patch
+net-sonic-use-mmio-accessors.patch
+net-sonic-fix-interface-error-stats-collection.patch
+net-sonic-fix-receive-buffer-handling.patch
+net-sonic-avoid-needless-receive-descriptor-eol-flag-updates.patch
+net-sonic-improve-receive-descriptor-status-flag-check.patch
+net-sonic-fix-receive-buffer-replenishment.patch
+net-sonic-quiesce-sonic-before-re-initializing-descriptor-memory.patch
+net-sonic-fix-command-register-usage.patch
+net-sonic-fix-cam-initialization.patch
+net-sonic-prevent-tx-watchdog-timeout.patch
+libertas-fix-two-buffer-overflows-at-parsing-bss-descriptor.patch
+media-v4l2-ioctl.c-zero-reserved-fields-for-s-try_fmt.patch