void wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status) { struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; u32 buf_size; u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK; u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; u32 rx_counter; u32 mem_block; u32 pkt_length; u32 pkt_offset; u8 hlid; bool unaligned = false; while (drv_rx_counter != fw_rx_counter) { buf_size = 0; rx_counter = drv_rx_counter; while (rx_counter != fw_rx_counter) { pkt_length = wl12xx_rx_get_buf_size(status, rx_counter); if (buf_size + pkt_length > WL1271_AGGR_BUFFER_SIZE) break; buf_size += pkt_length; rx_counter++; rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; } if (buf_size == 0) { wl1271_warning("received empty data"); break; } if (wl->chip.id != CHIP_ID_1283_PG20) { /* */ mem_block = wl12xx_rx_get_mem_block(status, drv_rx_counter); wl->rx_mem_pool_addr.addr = (mem_block << 8) + le32_to_cpu(wl_mem_map->packet_memory_pool_start); wl->rx_mem_pool_addr.addr_extra = wl->rx_mem_pool_addr.addr + 4; wl1271_write(wl, WL1271_SLV_REG_DATA, &wl->rx_mem_pool_addr, sizeof(wl->rx_mem_pool_addr), false); } /* */ wl1271_read(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, buf_size, true); /* */ pkt_offset = 0; while (pkt_offset < buf_size) { pkt_length = wl12xx_rx_get_buf_size(status, drv_rx_counter); unaligned = wl12xx_rx_get_unaligned(status, drv_rx_counter); /* */ if (wl1271_rx_handle_data(wl, wl->aggr_buf + pkt_offset, pkt_length, unaligned, &hlid) == 1) { if (hlid < WL12XX_MAX_LINKS) __set_bit(hlid, active_hlids); else WARN(1, "hlid exceeded WL12XX_MAX_LINKS " "(%d)\n", hlid); } wl->rx_counter++; drv_rx_counter++; drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; pkt_offset += pkt_length; } } /* */ if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION) wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); wl12xx_rearm_rx_streaming(wl, active_hlids); }
int wl12xx_rx(struct wl1271 *wl, struct wl12xx_fw_status *status) { struct wl1271_acx_mem_map *wl_mem_map = wl->target_mem_map; unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; u32 buf_size; u32 fw_rx_counter = status->fw_rx_counter & NUM_RX_PKT_DESC_MOD_MASK; u32 drv_rx_counter = wl->rx_counter & NUM_RX_PKT_DESC_MOD_MASK; u32 rx_counter; u32 mem_block; u32 pkt_length; u32 pkt_offset; u8 hlid; bool unaligned = false; int ret = 0; while (drv_rx_counter != fw_rx_counter) { buf_size = 0; rx_counter = drv_rx_counter; while (rx_counter != fw_rx_counter) { pkt_length = wl12xx_rx_get_buf_size(status, rx_counter); if (buf_size + pkt_length > WL1271_AGGR_BUFFER_SIZE) break; buf_size += pkt_length; rx_counter++; rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; } if (buf_size == 0) { wl1271_warning("received empty data"); break; } if (wl->chip.id != CHIP_ID_1283_PG20) { /* * Choose the block we want to read * For aggregated packets, only the first memory block * should be retrieved. The FW takes care of the rest. */ mem_block = wl12xx_rx_get_mem_block(status, drv_rx_counter); wl->rx_mem_pool_addr->addr = (mem_block << 8) + le32_to_cpu(wl_mem_map->packet_memory_pool_start); wl->rx_mem_pool_addr->addr_extra = wl->rx_mem_pool_addr->addr + 4; ret = wl1271_write(wl, WL1271_SLV_REG_DATA, wl->rx_mem_pool_addr, sizeof(*wl->rx_mem_pool_addr), false); if (ret < 0) goto out; } /* Read all available packets at once */ ret = wl1271_read(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, buf_size, true); if (ret < 0) goto out; /* Split data into separate packets */ pkt_offset = 0; while (pkt_offset < buf_size) { pkt_length = wl12xx_rx_get_buf_size(status, drv_rx_counter); unaligned = wl12xx_rx_get_unaligned(status, drv_rx_counter); /* * the handle data call can only fail in memory-outage * conditions, in that case the received frame will just * be dropped. */ if (wl1271_rx_handle_data(wl, wl->aggr_buf + pkt_offset, pkt_length, unaligned, &hlid) == 1) { if (hlid < WL12XX_MAX_LINKS) __set_bit(hlid, active_hlids); else WARN(1, "hlid exceeded WL12XX_MAX_LINKS " "(%d)\n", hlid); } wl->rx_counter++; drv_rx_counter++; drv_rx_counter &= NUM_RX_PKT_DESC_MOD_MASK; pkt_offset += pkt_length; } } /* * Write the driver's packet counter to the FW. This is only required * for older hardware revisions */ if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION) { ret = wl1271_write32(wl, RX_DRIVER_COUNTER_ADDRESS, wl->rx_counter); if (ret < 0) goto out; } wl12xx_rearm_rx_streaming(wl, active_hlids); out: return ret; }