@@ -370,16 +370,6 @@ m_can_txe_fifo_read(struct m_can_classdev *cdev, u32 fgi, u32 offset, u32 *val)
return cdev->ops->read_fifo(cdev, addr_offset, val, 1);
}
-static inline bool _m_can_tx_fifo_full(u32 txfqs)
-{
- return !!(txfqs & TXFQS_TFQF);
-}
-
-static inline bool m_can_tx_fifo_full(struct m_can_classdev *cdev)
-{
- return _m_can_tx_fifo_full(m_can_read(cdev, M_CAN_TXFQS));
-}
-
static void m_can_config_endisable(struct m_can_classdev *cdev, bool enable)
{
u32 cccr = m_can_read(cdev, M_CAN_CCCR);
@@ -1030,15 +1020,30 @@ static void m_can_tx_update_stats(struct m_can_classdev *cdev,
static void m_can_finish_tx(struct m_can_classdev *cdev, int transmitted)
{
spin_lock(&cdev->tx_handling_spinlock);
+ if (cdev->tx_fifo_in_flight >= cdev->tx_fifo_size && transmitted > 0)
+ netif_wake_queue(cdev->net);
cdev->tx_fifo_in_flight -= transmitted;
spin_unlock(&cdev->tx_handling_spinlock);
}
-static void m_can_start_tx(struct m_can_classdev *cdev)
+static netdev_tx_t m_can_start_tx(struct m_can_classdev *cdev)
{
+ int tx_fifo_in_flight;
+
spin_lock(&cdev->tx_handling_spinlock);
- ++cdev->tx_fifo_in_flight;
+ tx_fifo_in_flight = cdev->tx_fifo_in_flight + 1;
+ if (tx_fifo_in_flight >= cdev->tx_fifo_size) {
+ netif_stop_queue(cdev->net);
+ if (tx_fifo_in_flight > cdev->tx_fifo_size) {
+ netdev_err(cdev->net, "hard_xmit called while TX FIFO full\n");
+ spin_unlock(&cdev->tx_handling_spinlock);
+ return NETDEV_TX_BUSY;
+ }
+ }
+ cdev->tx_fifo_in_flight = tx_fifo_in_flight;
spin_unlock(&cdev->tx_handling_spinlock);
+
+ return NETDEV_TX_OK;
}
static int m_can_echo_tx_event(struct net_device *dev)
@@ -1182,7 +1187,6 @@ static irqreturn_t m_can_isr(int irq, void *dev_id)
if (cdev->is_peripheral)
timestamp = m_can_get_timestamp(cdev);
m_can_tx_update_stats(cdev, 0, timestamp);
- netif_wake_queue(dev);
m_can_finish_tx(cdev, 1);
}
} else {
@@ -1190,10 +1194,6 @@ static irqreturn_t m_can_isr(int irq, void *dev_id)
/* New TX FIFO Element arrived */
if (m_can_echo_tx_event(dev) != 0)
goto out_fail;
-
- if (netif_queue_stopped(dev) &&
- !m_can_tx_fifo_full(cdev))
- netif_wake_queue(dev);
}
}
@@ -1714,7 +1714,6 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev,
struct net_device *dev = cdev->net;
struct id_and_dlc fifo_header;
u32 cccr, fdflags;
- u32 txfqs;
int err;
int putidx;
@@ -1770,24 +1769,6 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev,
char buf[TXB_ELEMENT_SIZE];
/* Transmit routine for version >= v3.1.x */
- txfqs = m_can_read(cdev, M_CAN_TXFQS);
-
- /* Check if FIFO full */
- if (_m_can_tx_fifo_full(txfqs)) {
- /* This shouldn't happen */
- netif_stop_queue(dev);
- netdev_warn(dev,
- "TX queue active although FIFO is full.");
-
- if (cdev->is_peripheral) {
- kfree_skb(skb);
- dev->stats.tx_dropped++;
- return NETDEV_TX_OK;
- } else {
- return NETDEV_TX_BUSY;
- }
- }
-
/* get put index for frame */
putidx = cdev->tx_fifo_putidx;
@@ -1824,11 +1805,6 @@ static netdev_tx_t m_can_tx_handler(struct m_can_classdev *cdev,
m_can_write(cdev, M_CAN_TXBAR, (1 << putidx));
cdev->tx_fifo_putidx = (++cdev->tx_fifo_putidx >= cdev->can.echo_skb_max ?
0 : cdev->tx_fifo_putidx);
-
- /* stop network queue if fifo full */
- if (m_can_tx_fifo_full(cdev) ||
- m_can_next_echo_skb_occupied(dev, putidx))
- netif_stop_queue(dev);
}
return NETDEV_TX_OK;
@@ -1862,14 +1838,16 @@ static void m_can_tx_queue_skb(struct m_can_classdev *cdev, struct sk_buff *skb)
static netdev_tx_t m_can_start_peripheral_xmit(struct m_can_classdev *cdev,
struct sk_buff *skb)
{
+ netdev_tx_t err;
+
if (cdev->can.state == CAN_STATE_BUS_OFF) {
m_can_clean(cdev->net);
return NETDEV_TX_OK;
}
- netif_stop_queue(cdev->net);
-
- m_can_start_tx(cdev);
+ err = m_can_start_tx(cdev);
+ if (err != NETDEV_TX_OK)
+ return err;
m_can_tx_queue_skb(cdev, skb);
@@ -1879,7 +1857,11 @@ static netdev_tx_t m_can_start_peripheral_xmit(struct m_can_classdev *cdev,
static netdev_tx_t m_can_start_fast_xmit(struct m_can_classdev *cdev,
struct sk_buff *skb)
{
- m_can_start_tx(cdev);
+ netdev_tx_t err;
+
+ err = m_can_start_tx(cdev);
+ if (err != NETDEV_TX_OK)
+ return err;
return m_can_tx_handler(cdev, skb);
}