static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, struct sk_buff *skb, u8 port) { struct sdio_mmc_card *card = adapter->card; s32 f_do_rx_aggr = 0; s32 f_do_rx_cur = 0; s32 f_aggr_cur = 0; struct sk_buff *skb_deaggr; u32 pind; u32 pkt_len, pkt_type = 0; u8 *curr_ptr; u32 rx_len = skb->len; if (port == CTRL_PORT) { dev_dbg(adapter->dev, "info: %s: no aggregation for cmd " "response\n", __func__); f_do_rx_cur = 1; goto rx_curr_single; } if (!card->mpa_rx.enabled) { dev_dbg(adapter->dev, "info: %s: rx aggregation disabled\n", __func__); f_do_rx_cur = 1; goto rx_curr_single; } if (card->mp_rd_bitmap & (~((u16) CTRL_PORT_MASK))) { dev_dbg(adapter->dev, "info: %s: not last packet\n", __func__); if (MP_RX_AGGR_IN_PROGRESS(card)) { if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) { f_aggr_cur = 1; } else { f_do_rx_aggr = 1; f_do_rx_cur = 1; } } else { f_aggr_cur = 1; } } else { dev_dbg(adapter->dev, "info: %s: last packet\n", __func__); if (MP_RX_AGGR_IN_PROGRESS(card)) { f_do_rx_aggr = 1; if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) f_aggr_cur = 1; else f_do_rx_cur = 1; } else { f_do_rx_cur = 1; } } if (f_aggr_cur) { dev_dbg(adapter->dev, "info: current packet aggregation\n"); MP_RX_AGGR_SETUP(card, skb, port); if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) || MP_RX_AGGR_PORT_LIMIT_REACHED(card)) { dev_dbg(adapter->dev, "info: %s: aggregated packet " "limit reached\n", __func__); f_do_rx_aggr = 1; } } if (f_do_rx_aggr) { dev_dbg(adapter->dev, "info: do_rx_aggr: num of packets: %d\n", card->mpa_rx.pkt_cnt); if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf, card->mpa_rx.buf_len, (adapter->ioport | 0x1000 | (card->mpa_rx.ports << 4)) + card->mpa_rx.start_port, 1)) goto error; curr_ptr = card->mpa_rx.buf; for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) { pkt_len = *(u16 *) &curr_ptr[0]; pkt_type = *(u16 *) &curr_ptr[2]; skb_deaggr = card->mpa_rx.skb_arr[pind]; if ((pkt_type == MWIFIEX_TYPE_DATA) && (pkt_len <= card->mpa_rx.len_arr[pind])) { memcpy(skb_deaggr->data, curr_ptr, pkt_len); skb_trim(skb_deaggr, pkt_len); mwifiex_decode_rx_packet(adapter, skb_deaggr, pkt_type); } else { dev_err(adapter->dev, "wrong aggr pkt:" " type=%d len=%d max_len=%d\n", pkt_type, pkt_len, card->mpa_rx.len_arr[pind]); dev_kfree_skb_any(skb_deaggr); } curr_ptr += card->mpa_rx.len_arr[pind]; } MP_RX_AGGR_BUF_RESET(card); } rx_curr_single: if (f_do_rx_cur) { dev_dbg(adapter->dev, "info: RX: port: %d, rx_len: %d\n", port, rx_len); if (mwifiex_sdio_card_to_host(adapter, &pkt_type, skb->data, skb->len, adapter->ioport + port)) goto error; mwifiex_decode_rx_packet(adapter, skb, pkt_type); } return 0; error: if (MP_RX_AGGR_IN_PROGRESS(card)) { for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) { skb_deaggr = card->mpa_rx.skb_arr[pind]; dev_kfree_skb_any(skb_deaggr); } MP_RX_AGGR_BUF_RESET(card); } if (f_do_rx_cur) dev_kfree_skb_any(skb); return -1; }
/* * This function transfers received packets from card to driver, performing * aggregation if required. * * For data received on control port, or if aggregation is disabled, the * received buffers are uploaded as separate packets. However, if aggregation * is enabled and required, the buffers are copied onto an aggregation buffer, * provided there is space left, processed and finally uploaded. */ static int mwifiex_sdio_card_to_host_mp_aggr(struct mwifiex_adapter *adapter, struct sk_buff *skb, u8 port) { struct sdio_mmc_card *card = adapter->card; s32 f_do_rx_aggr = 0; s32 f_do_rx_cur = 0; s32 f_aggr_cur = 0; struct sk_buff *skb_deaggr; u32 pind; u32 pkt_len, pkt_type = 0; u8 *curr_ptr; u32 rx_len = skb->len; if (port == CTRL_PORT) { /* Read the command Resp without aggr */ dev_dbg(adapter->dev, "info: %s: no aggregation for cmd " "response\n", __func__); f_do_rx_cur = 1; goto rx_curr_single; } if (!card->mpa_rx.enabled) { dev_dbg(adapter->dev, "info: %s: rx aggregation disabled\n", __func__); f_do_rx_cur = 1; goto rx_curr_single; } if (card->mp_rd_bitmap & (~((u16) CTRL_PORT_MASK))) { /* Some more data RX pending */ dev_dbg(adapter->dev, "info: %s: not last packet\n", __func__); if (MP_RX_AGGR_IN_PROGRESS(card)) { if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) { f_aggr_cur = 1; } else { /* No room in Aggr buf, do rx aggr now */ f_do_rx_aggr = 1; f_do_rx_cur = 1; } } else { /* Rx aggr not in progress */ f_aggr_cur = 1; } } else { /* No more data RX pending */ dev_dbg(adapter->dev, "info: %s: last packet\n", __func__); if (MP_RX_AGGR_IN_PROGRESS(card)) { f_do_rx_aggr = 1; if (MP_RX_AGGR_BUF_HAS_ROOM(card, skb->len)) f_aggr_cur = 1; else /* No room in Aggr buf, do rx aggr now */ f_do_rx_cur = 1; } else { f_do_rx_cur = 1; } } if (f_aggr_cur) { dev_dbg(adapter->dev, "info: current packet aggregation\n"); /* Curr pkt can be aggregated */ MP_RX_AGGR_SETUP(card, skb, port); if (MP_RX_AGGR_PKT_LIMIT_REACHED(card) || MP_RX_AGGR_PORT_LIMIT_REACHED(card)) { dev_dbg(adapter->dev, "info: %s: aggregated packet " "limit reached\n", __func__); /* No more pkts allowed in Aggr buf, rx it */ f_do_rx_aggr = 1; } } if (f_do_rx_aggr) { /* do aggr RX now */ dev_dbg(adapter->dev, "info: do_rx_aggr: num of packets: %d\n", card->mpa_rx.pkt_cnt); if (mwifiex_read_data_sync(adapter, card->mpa_rx.buf, card->mpa_rx.buf_len, (adapter->ioport | 0x1000 | (card->mpa_rx.ports << 4)) + card->mpa_rx.start_port, 1)) return -1; curr_ptr = card->mpa_rx.buf; for (pind = 0; pind < card->mpa_rx.pkt_cnt; pind++) { /* get curr PKT len & type */ pkt_len = *(u16 *) &curr_ptr[0]; pkt_type = *(u16 *) &curr_ptr[2]; /* copy pkt to deaggr buf */ skb_deaggr = card->mpa_rx.skb_arr[pind]; if ((pkt_type == MWIFIEX_TYPE_DATA) && (pkt_len <= card->mpa_rx.len_arr[pind])) { memcpy(skb_deaggr->data, curr_ptr, pkt_len); skb_trim(skb_deaggr, pkt_len); /* Process de-aggr packet */ mwifiex_decode_rx_packet(adapter, skb_deaggr, pkt_type); } else { dev_err(adapter->dev, "wrong aggr pkt:" " type=%d len=%d max_len=%d\n", pkt_type, pkt_len, card->mpa_rx.len_arr[pind]); dev_kfree_skb_any(skb_deaggr); } curr_ptr += card->mpa_rx.len_arr[pind]; } MP_RX_AGGR_BUF_RESET(card); } rx_curr_single: if (f_do_rx_cur) { dev_dbg(adapter->dev, "info: RX: port: %d, rx_len: %d\n", port, rx_len); if (mwifiex_sdio_card_to_host(adapter, &pkt_type, skb->data, skb->len, adapter->ioport + port)) return -1; mwifiex_decode_rx_packet(adapter, skb, pkt_type); } return 0; }