|
30 | 30 | #define MTK_WED_RX_PAGE_BUF_PER_PAGE (PAGE_SIZE / 128) |
31 | 31 | #define MTK_WED_RX_RING_SIZE 1536 |
32 | 32 | #define MTK_WED_RX_PG_BM_CNT 8192 |
| 33 | +#define MTK_WED_AMSDU_BUF_SIZE (PAGE_SIZE << 4) |
| 34 | +#define MTK_WED_AMSDU_NPAGES 32 |
33 | 35 |
|
34 | 36 | #define MTK_WED_TX_RING_SIZE 2048 |
35 | 37 | #define MTK_WED_WDMA_RING_SIZE 1024 |
@@ -173,6 +175,23 @@ mtk_wdma_rx_reset(struct mtk_wed_device *dev) |
173 | 175 | return ret; |
174 | 176 | } |
175 | 177 |
|
| 178 | +static u32 |
| 179 | +mtk_wed_check_busy(struct mtk_wed_device *dev, u32 reg, u32 mask) |
| 180 | +{ |
| 181 | + return !!(wed_r32(dev, reg) & mask); |
| 182 | +} |
| 183 | + |
| 184 | +static int |
| 185 | +mtk_wed_poll_busy(struct mtk_wed_device *dev, u32 reg, u32 mask) |
| 186 | +{ |
| 187 | + int sleep = 15000; |
| 188 | + int timeout = 100 * sleep; |
| 189 | + u32 val; |
| 190 | + |
| 191 | + return read_poll_timeout(mtk_wed_check_busy, val, !val, sleep, |
| 192 | + timeout, false, dev, reg, mask); |
| 193 | +} |
| 194 | + |
176 | 195 | static void |
177 | 196 | mtk_wdma_tx_reset(struct mtk_wed_device *dev) |
178 | 197 | { |
@@ -335,6 +354,118 @@ mtk_wed_assign(struct mtk_wed_device *dev) |
335 | 354 | return hw; |
336 | 355 | } |
337 | 356 |
|
| 357 | +static int |
| 358 | +mtk_wed_amsdu_buffer_alloc(struct mtk_wed_device *dev) |
| 359 | +{ |
| 360 | + struct mtk_wed_hw *hw = dev->hw; |
| 361 | + struct mtk_wed_amsdu *wed_amsdu; |
| 362 | + int i; |
| 363 | + |
| 364 | + if (!mtk_wed_is_v3_or_greater(hw)) |
| 365 | + return 0; |
| 366 | + |
| 367 | + wed_amsdu = devm_kcalloc(hw->dev, MTK_WED_AMSDU_NPAGES, |
| 368 | + sizeof(*wed_amsdu), GFP_KERNEL); |
| 369 | + if (!wed_amsdu) |
| 370 | + return -ENOMEM; |
| 371 | + |
| 372 | + for (i = 0; i < MTK_WED_AMSDU_NPAGES; i++) { |
| 373 | + void *ptr; |
| 374 | + |
| 375 | + /* each segment is 64K */ |
| 376 | + ptr = (void *)__get_free_pages(GFP_KERNEL | __GFP_NOWARN | |
| 377 | + __GFP_ZERO | __GFP_COMP | |
| 378 | + GFP_DMA32, |
| 379 | + get_order(MTK_WED_AMSDU_BUF_SIZE)); |
| 380 | + if (!ptr) |
| 381 | + goto error; |
| 382 | + |
| 383 | + wed_amsdu[i].txd = ptr; |
| 384 | + wed_amsdu[i].txd_phy = dma_map_single(hw->dev, ptr, |
| 385 | + MTK_WED_AMSDU_BUF_SIZE, |
| 386 | + DMA_TO_DEVICE); |
| 387 | + if (dma_mapping_error(hw->dev, wed_amsdu[i].txd_phy)) |
| 388 | + goto error; |
| 389 | + } |
| 390 | + dev->hw->wed_amsdu = wed_amsdu; |
| 391 | + |
| 392 | + return 0; |
| 393 | + |
| 394 | +error: |
| 395 | + for (i--; i >= 0; i--) |
| 396 | + dma_unmap_single(hw->dev, wed_amsdu[i].txd_phy, |
| 397 | + MTK_WED_AMSDU_BUF_SIZE, DMA_TO_DEVICE); |
| 398 | + return -ENOMEM; |
| 399 | +} |
| 400 | + |
| 401 | +static void |
| 402 | +mtk_wed_amsdu_free_buffer(struct mtk_wed_device *dev) |
| 403 | +{ |
| 404 | + struct mtk_wed_amsdu *wed_amsdu = dev->hw->wed_amsdu; |
| 405 | + int i; |
| 406 | + |
| 407 | + if (!wed_amsdu) |
| 408 | + return; |
| 409 | + |
| 410 | + for (i = 0; i < MTK_WED_AMSDU_NPAGES; i++) { |
| 411 | + dma_unmap_single(dev->hw->dev, wed_amsdu[i].txd_phy, |
| 412 | + MTK_WED_AMSDU_BUF_SIZE, DMA_TO_DEVICE); |
| 413 | + free_pages((unsigned long)wed_amsdu[i].txd, |
| 414 | + get_order(MTK_WED_AMSDU_BUF_SIZE)); |
| 415 | + } |
| 416 | +} |
| 417 | + |
| 418 | +static int |
| 419 | +mtk_wed_amsdu_init(struct mtk_wed_device *dev) |
| 420 | +{ |
| 421 | + struct mtk_wed_amsdu *wed_amsdu = dev->hw->wed_amsdu; |
| 422 | + int i, ret; |
| 423 | + |
| 424 | + if (!wed_amsdu) |
| 425 | + return 0; |
| 426 | + |
| 427 | + for (i = 0; i < MTK_WED_AMSDU_NPAGES; i++) |
| 428 | + wed_w32(dev, MTK_WED_AMSDU_HIFTXD_BASE_L(i), |
| 429 | + wed_amsdu[i].txd_phy); |
| 430 | + |
| 431 | + /* init all sta parameter */ |
| 432 | + wed_w32(dev, MTK_WED_AMSDU_STA_INFO_INIT, MTK_WED_AMSDU_STA_RMVL | |
| 433 | + MTK_WED_AMSDU_STA_WTBL_HDRT_MODE | |
| 434 | + FIELD_PREP(MTK_WED_AMSDU_STA_MAX_AMSDU_LEN, |
| 435 | + dev->wlan.amsdu_max_len >> 8) | |
| 436 | + FIELD_PREP(MTK_WED_AMSDU_STA_MAX_AMSDU_NUM, |
| 437 | + dev->wlan.amsdu_max_subframes)); |
| 438 | + |
| 439 | + wed_w32(dev, MTK_WED_AMSDU_STA_INFO, MTK_WED_AMSDU_STA_INFO_DO_INIT); |
| 440 | + |
| 441 | + ret = mtk_wed_poll_busy(dev, MTK_WED_AMSDU_STA_INFO, |
| 442 | + MTK_WED_AMSDU_STA_INFO_DO_INIT); |
| 443 | + if (ret) { |
| 444 | + dev_err(dev->hw->dev, "amsdu initialization failed\n"); |
| 445 | + return ret; |
| 446 | + } |
| 447 | + |
| 448 | + /* init partial amsdu offload txd src */ |
| 449 | + wed_set(dev, MTK_WED_AMSDU_HIFTXD_CFG, |
| 450 | + FIELD_PREP(MTK_WED_AMSDU_HIFTXD_SRC, dev->hw->index)); |
| 451 | + |
| 452 | + /* init qmem */ |
| 453 | + wed_set(dev, MTK_WED_AMSDU_PSE, MTK_WED_AMSDU_PSE_RESET); |
| 454 | + ret = mtk_wed_poll_busy(dev, MTK_WED_MON_AMSDU_QMEM_STS1, BIT(29)); |
| 455 | + if (ret) { |
| 456 | + pr_info("%s: amsdu qmem initialization failed\n", __func__); |
| 457 | + return ret; |
| 458 | + } |
| 459 | + |
| 460 | + /* eagle E1 PCIE1 tx ring 22 flow control issue */ |
| 461 | + if (dev->wlan.id == 0x7991) |
| 462 | + wed_clr(dev, MTK_WED_AMSDU_FIFO, MTK_WED_AMSDU_IS_PRIOR0_RING); |
| 463 | + |
| 464 | + wed_set(dev, MTK_WED_CTRL, MTK_WED_CTRL_TX_AMSDU_EN); |
| 465 | + |
| 466 | + return 0; |
| 467 | +} |
| 468 | + |
338 | 469 | static int |
339 | 470 | mtk_wed_tx_buffer_alloc(struct mtk_wed_device *dev) |
340 | 471 | { |
@@ -709,6 +840,7 @@ __mtk_wed_detach(struct mtk_wed_device *dev) |
709 | 840 |
|
710 | 841 | mtk_wdma_rx_reset(dev); |
711 | 842 | mtk_wed_reset(dev, MTK_WED_RESET_WED); |
| 843 | + mtk_wed_amsdu_free_buffer(dev); |
712 | 844 | mtk_wed_free_tx_buffer(dev); |
713 | 845 | mtk_wed_free_tx_rings(dev); |
714 | 846 |
|
@@ -1129,23 +1261,6 @@ mtk_wed_ring_reset(struct mtk_wed_ring *ring, int size, bool tx) |
1129 | 1261 | } |
1130 | 1262 | } |
1131 | 1263 |
|
1132 | | -static u32 |
1133 | | -mtk_wed_check_busy(struct mtk_wed_device *dev, u32 reg, u32 mask) |
1134 | | -{ |
1135 | | - return !!(wed_r32(dev, reg) & mask); |
1136 | | -} |
1137 | | - |
1138 | | -static int |
1139 | | -mtk_wed_poll_busy(struct mtk_wed_device *dev, u32 reg, u32 mask) |
1140 | | -{ |
1141 | | - int sleep = 15000; |
1142 | | - int timeout = 100 * sleep; |
1143 | | - u32 val; |
1144 | | - |
1145 | | - return read_poll_timeout(mtk_wed_check_busy, val, !val, sleep, |
1146 | | - timeout, false, dev, reg, mask); |
1147 | | -} |
1148 | | - |
1149 | 1264 | static int |
1150 | 1265 | mtk_wed_rx_reset(struct mtk_wed_device *dev) |
1151 | 1266 | { |
@@ -1692,6 +1807,7 @@ mtk_wed_start(struct mtk_wed_device *dev, u32 irq_mask) |
1692 | 1807 | } |
1693 | 1808 |
|
1694 | 1809 | mtk_wed_set_512_support(dev, dev->wlan.wcid_512); |
| 1810 | + mtk_wed_amsdu_init(dev); |
1695 | 1811 |
|
1696 | 1812 | mtk_wed_dma_enable(dev); |
1697 | 1813 | dev->running = true; |
@@ -1748,6 +1864,10 @@ mtk_wed_attach(struct mtk_wed_device *dev) |
1748 | 1864 | if (ret) |
1749 | 1865 | goto out; |
1750 | 1866 |
|
| 1867 | + ret = mtk_wed_amsdu_buffer_alloc(dev); |
| 1868 | + if (ret) |
| 1869 | + goto out; |
| 1870 | + |
1751 | 1871 | if (mtk_wed_get_rx_capa(dev)) { |
1752 | 1872 | ret = mtk_wed_rro_alloc(dev); |
1753 | 1873 | if (ret) |
|
0 commit comments