Verified Commit d7429134 authored by Marek Vasut's avatar Marek Vasut Committed by Sebastian Krzyszkowiak

redpine: Move card interrupt handling to RX thread

The interrupt handling of the RS911x is particularly heavy. For each RX
packet, the card does three SDIO transactions, one to read interrupt
status register, one to RX buffer length, one to read the RX packet(s).
This translates to ~330 uS per one cycle of interrupt handler. In case
there is more incoming traffic, this will be more.

The drivers/mmc/core/sdio_irq.c has the following comment, quote "Just
like traditional hard IRQ handlers, we expect SDIO IRQ handlers to be
quick and to the point, so that the holding of the host lock does not
cover too much work that doesn't require that lock to be held."

The RS911x interrupt handler does not fit that. This patch therefore
changes it such that the entire IRQ handler is moved to the RX thread
instead, and the interrupt handler only wakes the RX thread.

This is OK, because the interrupt handler only does things which can
also be done in the RX thread, that is, it checks for firmware loading
error(s), it checks buffer status, it checks whether a packet arrived
and if so, reads out the packet and passes it to network stack.

Moreover, this change permits removal of a code which allocated an
skbuff only to get 4-byte-aligned buffer, read up to 8kiB of data
into the skbuff, queue this skbuff into local private queue, then in
RX thread, this buffer is dequeued, the data in the skbuff as passed
to the RSI driver core, and the skbuff is deallocated. All this is
replaced by directly calling the RSI driver core with local buffer.
Signed-off-by: default avatarMarek Vasut <marex@denx.de>
parent f386c92a
......@@ -177,9 +177,7 @@ static void rsi_handle_interrupt(struct sdio_func *function)
if (adapter->priv->fsm_state == FSM_FW_NOT_LOADED)
return;
dev->sdio_irq_task = current;
rsi_interrupt_handler(adapter);
dev->sdio_irq_task = NULL;
rsi_set_event(&dev->rx_thread.event);
}
static void rsi_gspi_init(struct rsi_hw *adapter)
......@@ -1193,7 +1191,6 @@ static int rsi_init_sdio_interface(struct rsi_hw *adapter,
sdio_release_host(pfunction);
adapter->determine_event_timeout = rsi_sdio_determine_event_timeout;
adapter->process_isr_hci = rsi_interrupt_handler;
adapter->check_intr_status_reg = rsi_read_intr_status_reg;
#ifdef CONFIG_REDPINE_DEBUGFS
......@@ -1295,8 +1292,6 @@ static int rsi_probe(struct sdio_func *pfunction,
redpine_dbg(ERR_ZONE, "%s: Unable to init rx thrd\n", __func__);
goto fail_kill_thread;
}
skb_queue_head_init(&sdev->rx_q.head);
sdev->rx_q.num_rx_pkts = 0;
/*Receive buffer for handling RX interrupts in case of memory full*/
sdev->temp_rcv_buf = kzalloc((RCV_BUFF_LEN *4), GFP_KERNEL);
......
......@@ -74,49 +74,26 @@ int rsi_sdio_master_access_msword(struct rsi_hw *adapter,
return status;
}
static void rsi_rx_handler(struct rsi_hw *adapter);
void rsi_sdio_rx_thread(struct rsi_common *common)
{
struct rsi_hw *adapter = common->priv;
struct rsi_91x_sdiodev *sdev = adapter->rsi_dev;
struct sk_buff *skb;
int status;
bool done = false;
do {
status = rsi_wait_event(&sdev->rx_thread.event,
status = rsi_wait_event(&sdev->rx_thread.event,
EVENT_WAIT_FOREVER);
if (status < 0)
break;
if (atomic_read(&sdev->rx_thread.thread_done))
break;
while (true) {
skb = skb_dequeue(&sdev->rx_q.head);
if (!skb)
break;
status = redpine_read_pkt(common, skb->data, skb->len);
if (status) {
redpine_dbg(ERR_ZONE, "Failed to read the packet\n");
dev_kfree_skb(skb);
return;
}
dev_kfree_skb(skb);
if (sdev->rx_q.num_rx_pkts > 0)
sdev->rx_q.num_rx_pkts--;
if (atomic_read(&sdev->rx_thread.thread_done)) {
done = true;
break;
}
}
rsi_reset_event(&sdev->rx_thread.event);
if (done)
break;
} while (1);
rsi_rx_handler(adapter);
} while (!atomic_read(&sdev->rx_thread.thread_done));
redpine_dbg(INFO_ZONE, "%s: Terminated SDIO RX thread\n", __func__);
skb_queue_purge(&sdev->rx_q.head);
atomic_inc(&sdev->rx_thread.thread_done);
complete_and_exit(&sdev->rx_thread.completion, 0);
}
......@@ -138,7 +115,6 @@ static int rsi_process_pkt(struct rsi_common *common)
int status = 0;
u8 value = 0;
u8 protocol = 0, unaggr_pkt = 0;
struct sk_buff *skb;
#define COEX_PKT 0
......@@ -179,41 +155,18 @@ static int rsi_process_pkt(struct rsi_common *common)
unaggr_pkt = 1;
rcv_pkt_len = (num_blks * 256);
if (dev->rx_q.num_rx_pkts >= RSI_SDIO_MAX_RX_PKTS)
{
redpine_dbg(ISR_ZONE, "%s,%d: Reached MAX RX_Q size,"
"dropping the packet\n",__func__,__LINE__);
goto DROP_PKT;
}
skb = dev_alloc_skb(rcv_pkt_len);
if (!skb)
{
redpine_dbg(ERR_ZONE, "%s,%d: Failed to allocate rx packet buffer,"
"dropping packet\n",__func__,__LINE__);
goto DROP_PKT;
}
skb_put(skb, rcv_pkt_len);
status = rsi_sdio_host_intf_read_pkt(adapter, skb->data, skb->len);
status = rsi_sdio_host_intf_read_pkt(adapter, dev->pktbuffer, rcv_pkt_len);
if (status) {
redpine_dbg(ERR_ZONE, "%s,%d: Failed to read packet from card\n",
__func__,__LINE__);
dev_kfree_skb(skb);
return status;
}
skb_queue_tail(&dev->rx_q.head, skb);
dev->rx_q.num_rx_pkts++;
rsi_set_event(&dev->rx_thread.event);
return 0;
DROP_PKT:
status = rsi_sdio_host_intf_read_pkt(adapter, dev->temp_rcv_buf, rcv_pkt_len);
if (status)
redpine_dbg(ERR_ZONE, "%s,%d: Failed to read packet from card\n",
__func__,__LINE__);
rsi_set_event(&dev->rx_thread.event);
status = redpine_read_pkt(common, dev->pktbuffer, rcv_pkt_len);
if (status) {
redpine_dbg(ERR_ZONE, "Failed to read the packet\n");
return status;
}
return 0;
}
......@@ -320,18 +273,17 @@ int rsi_read_intr_status_reg(struct rsi_hw *adapter)
}
/**
* rsi_interrupt_handler() - This function read and process SDIO interrupts.
* rsi_rx_handler() - This function read and process SDIO interrupts.
* @adapter: Pointer to the adapter structure.
*
* Return: None.
*/
void rsi_interrupt_handler(struct rsi_hw *adapter)
static void rsi_rx_handler(struct rsi_hw *adapter)
{
struct rsi_common *common = adapter->priv;
struct rsi_91x_sdiodev *dev =
(struct rsi_91x_sdiodev *)adapter->rsi_dev;
int status;
enum sdio_interrupt_type isr_type;
u8 isr_status = 0;
u8 fw_status = 0;
......
......@@ -127,12 +127,6 @@ struct receive_info {
u32 buf_available_counter;
};
#define RSI_SDIO_MAX_RX_PKTS 100
struct rsi_sdio_rx_q {
u8 num_rx_pkts;
struct sk_buff_head head;
};
struct rsi_91x_sdiodev {
struct sdio_func *pfunction;
struct task_struct *sdio_irq_task;
......@@ -145,13 +139,12 @@ struct rsi_91x_sdiodev {
u32 tx_blk_size;
u8 write_fail;
u8 buff_status_updated;
struct rsi_sdio_rx_q rx_q;
struct rsi_thread rx_thread;
u8 *temp_rcv_buf;
u8 pktbuffer[8192] __aligned(4);
};
void redpine_gpio_init(struct rsi_common *common);
void rsi_interrupt_handler(struct rsi_hw *adapter);
int rsi_init_sdio_slave_regs(struct rsi_hw *adapter);
int rsi_sdio_device_init(struct rsi_common *common);
int rsi_sdio_read_register(struct rsi_hw *adapter, u32 addr, u8 *data);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment