diff options
-rw-r--r-- | drivers/net/ethernet/oa_tc6.c | 52 |
1 files changed, 51 insertions, 1 deletions
diff --git a/drivers/net/ethernet/oa_tc6.c b/drivers/net/ethernet/oa_tc6.c index 72d95bad669f..d3510dc19273 100644 --- a/drivers/net/ethernet/oa_tc6.c +++ b/drivers/net/ethernet/oa_tc6.c @@ -126,6 +126,7 @@ struct oa_tc6 { u16 tx_credits; u8 rx_chunks_available; bool rx_buf_overflow; + bool int_flag; }; enum oa_tc6_header_type { @@ -1064,6 +1065,14 @@ static int oa_tc6_try_spi_transfer(struct oa_tc6 *tc6) spi_len = oa_tc6_prepare_spi_tx_buf_for_rx_chunks(tc6, spi_len); + if (tc6->int_flag) { + tc6->int_flag = false; + if (spi_len == 0) { + oa_tc6_add_empty_chunks_to_spi_buf(tc6, 1); + spi_len = OA_TC6_CHUNK_SIZE; + } + } + if (spi_len == 0) break; @@ -1098,8 +1107,11 @@ static int oa_tc6_spi_thread_handler(void *data) int ret; while (likely(!kthread_should_stop())) { - /* This kthread will be waken up if there is a tx skb */ + /* This kthread will be waken up if there is a tx skb or mac-phy + * interrupt to perform spi transfer with tx chunks. + */ wait_event_interruptible(tc6->spi_wq, tc6->waiting_tx_skb || + tc6->int_flag || kthread_should_stop()); if (kthread_should_stop()) @@ -1133,6 +1145,24 @@ static int oa_tc6_update_buffer_status_from_register(struct oa_tc6 *tc6) return 0; } +static irqreturn_t oa_tc6_macphy_isr(int irq, void *data) +{ + struct oa_tc6 *tc6 = data; + + /* MAC-PHY interrupt can occur for the following reasons. + * - availability of tx credits if it was 0 before and not reported in + * the previous rx footer. + * - availability of rx chunks if it was 0 before and not reported in + * the previous rx footer. + * - extended status event not reported in the previous rx footer. + */ + tc6->int_flag = true; + /* Wake spi kthread to perform spi transfer */ + wake_up_interruptible(&tc6->spi_wq); + + return IRQ_HANDLED; +} + /** * oa_tc6_start_xmit - function for sending the tx skb which consists ethernet * frame. @@ -1260,8 +1290,28 @@ struct oa_tc6 *oa_tc6_init(struct spi_device *spi, struct net_device *netdev) sched_set_fifo(tc6->spi_thread); + ret = devm_request_irq(&tc6->spi->dev, tc6->spi->irq, oa_tc6_macphy_isr, + IRQF_TRIGGER_FALLING, dev_name(&tc6->spi->dev), + tc6); + if (ret) { + dev_err(&tc6->spi->dev, "Failed to request macphy isr %d\n", + ret); + goto kthread_stop; + } + + /* oa_tc6_sw_reset_macphy() function resets and clears the MAC-PHY reset + * complete status. IRQ is also asserted on reset completion and it is + * remain asserted until MAC-PHY receives a data chunk. So performing an + * empty data chunk transmission will deassert the IRQ. Refer section + * 7.7 and 9.2.8.8 in the OPEN Alliance specification for more details. + */ + tc6->int_flag = true; + wake_up_interruptible(&tc6->spi_wq); + return tc6; +kthread_stop: + kthread_stop(tc6->spi_thread); phy_exit: oa_tc6_phy_exit(tc6); return NULL; |