1c8349639SHoratiu Vultur // SPDX-License-Identifier: GPL-2.0+ 2c8349639SHoratiu Vultur 3c8349639SHoratiu Vultur #include "lan966x_main.h" 4c8349639SHoratiu Vultur 5c8349639SHoratiu Vultur static int lan966x_fdma_channel_active(struct lan966x *lan966x) 6c8349639SHoratiu Vultur { 7c8349639SHoratiu Vultur return lan_rd(lan966x, FDMA_CH_ACTIVE); 8c8349639SHoratiu Vultur } 9c8349639SHoratiu Vultur 10c8349639SHoratiu Vultur static struct page *lan966x_fdma_rx_alloc_page(struct lan966x_rx *rx, 11c8349639SHoratiu Vultur struct lan966x_db *db) 12c8349639SHoratiu Vultur { 13c8349639SHoratiu Vultur struct lan966x *lan966x = rx->lan966x; 14c8349639SHoratiu Vultur dma_addr_t dma_addr; 15c8349639SHoratiu Vultur struct page *page; 16c8349639SHoratiu Vultur 17c8349639SHoratiu Vultur page = dev_alloc_pages(rx->page_order); 18c8349639SHoratiu Vultur if (unlikely(!page)) 19c8349639SHoratiu Vultur return NULL; 20c8349639SHoratiu Vultur 21c8349639SHoratiu Vultur dma_addr = dma_map_page(lan966x->dev, page, 0, 22c8349639SHoratiu Vultur PAGE_SIZE << rx->page_order, 23c8349639SHoratiu Vultur DMA_FROM_DEVICE); 24c8349639SHoratiu Vultur if (unlikely(dma_mapping_error(lan966x->dev, dma_addr))) 25c8349639SHoratiu Vultur goto free_page; 26c8349639SHoratiu Vultur 27c8349639SHoratiu Vultur db->dataptr = dma_addr; 28c8349639SHoratiu Vultur 29c8349639SHoratiu Vultur return page; 30c8349639SHoratiu Vultur 31c8349639SHoratiu Vultur free_page: 32c8349639SHoratiu Vultur __free_pages(page, rx->page_order); 33c8349639SHoratiu Vultur return NULL; 34c8349639SHoratiu Vultur } 35c8349639SHoratiu Vultur 36c8349639SHoratiu Vultur static void lan966x_fdma_rx_free_pages(struct lan966x_rx *rx) 37c8349639SHoratiu Vultur { 38c8349639SHoratiu Vultur struct lan966x *lan966x = rx->lan966x; 39c8349639SHoratiu Vultur struct lan966x_rx_dcb *dcb; 40c8349639SHoratiu Vultur struct lan966x_db *db; 41c8349639SHoratiu Vultur int i, j; 42c8349639SHoratiu Vultur 43c8349639SHoratiu Vultur for (i = 0; i < FDMA_DCB_MAX; ++i) { 44c8349639SHoratiu Vultur dcb = &rx->dcbs[i]; 45c8349639SHoratiu Vultur 46c8349639SHoratiu Vultur for (j = 0; j < FDMA_RX_DCB_MAX_DBS; ++j) { 47c8349639SHoratiu Vultur db = &dcb->db[j]; 48c8349639SHoratiu Vultur dma_unmap_single(lan966x->dev, 49c8349639SHoratiu Vultur (dma_addr_t)db->dataptr, 50c8349639SHoratiu Vultur PAGE_SIZE << rx->page_order, 51c8349639SHoratiu Vultur DMA_FROM_DEVICE); 52c8349639SHoratiu Vultur __free_pages(rx->page[i][j], rx->page_order); 53c8349639SHoratiu Vultur } 54c8349639SHoratiu Vultur } 55c8349639SHoratiu Vultur } 56c8349639SHoratiu Vultur 57c8349639SHoratiu Vultur static void lan966x_fdma_rx_add_dcb(struct lan966x_rx *rx, 58c8349639SHoratiu Vultur struct lan966x_rx_dcb *dcb, 59c8349639SHoratiu Vultur u64 nextptr) 60c8349639SHoratiu Vultur { 61c8349639SHoratiu Vultur struct lan966x_db *db; 62c8349639SHoratiu Vultur int i; 63c8349639SHoratiu Vultur 64c8349639SHoratiu Vultur for (i = 0; i < FDMA_RX_DCB_MAX_DBS; ++i) { 65c8349639SHoratiu Vultur db = &dcb->db[i]; 66c8349639SHoratiu Vultur db->status = FDMA_DCB_STATUS_INTR; 67c8349639SHoratiu Vultur } 68c8349639SHoratiu Vultur 69c8349639SHoratiu Vultur dcb->nextptr = FDMA_DCB_INVALID_DATA; 70c8349639SHoratiu Vultur dcb->info = FDMA_DCB_INFO_DATAL(PAGE_SIZE << rx->page_order); 71c8349639SHoratiu Vultur 72c8349639SHoratiu Vultur rx->last_entry->nextptr = nextptr; 73c8349639SHoratiu Vultur rx->last_entry = dcb; 74c8349639SHoratiu Vultur } 75c8349639SHoratiu Vultur 76c8349639SHoratiu Vultur static int lan966x_fdma_rx_alloc(struct lan966x_rx *rx) 77c8349639SHoratiu Vultur { 78c8349639SHoratiu Vultur struct lan966x *lan966x = rx->lan966x; 79c8349639SHoratiu Vultur struct lan966x_rx_dcb *dcb; 80c8349639SHoratiu Vultur struct lan966x_db *db; 81c8349639SHoratiu Vultur struct page *page; 82c8349639SHoratiu Vultur int i, j; 83c8349639SHoratiu Vultur int size; 84c8349639SHoratiu Vultur 85c8349639SHoratiu Vultur /* calculate how many pages are needed to allocate the dcbs */ 86c8349639SHoratiu Vultur size = sizeof(struct lan966x_rx_dcb) * FDMA_DCB_MAX; 87c8349639SHoratiu Vultur size = ALIGN(size, PAGE_SIZE); 88c8349639SHoratiu Vultur 89c8349639SHoratiu Vultur rx->dcbs = dma_alloc_coherent(lan966x->dev, size, &rx->dma, GFP_KERNEL); 90c8349639SHoratiu Vultur if (!rx->dcbs) 91c8349639SHoratiu Vultur return -ENOMEM; 92c8349639SHoratiu Vultur 93c8349639SHoratiu Vultur rx->last_entry = rx->dcbs; 94c8349639SHoratiu Vultur rx->db_index = 0; 95c8349639SHoratiu Vultur rx->dcb_index = 0; 96c8349639SHoratiu Vultur 97c8349639SHoratiu Vultur /* Now for each dcb allocate the dbs */ 98c8349639SHoratiu Vultur for (i = 0; i < FDMA_DCB_MAX; ++i) { 99c8349639SHoratiu Vultur dcb = &rx->dcbs[i]; 100c8349639SHoratiu Vultur dcb->info = 0; 101c8349639SHoratiu Vultur 102c8349639SHoratiu Vultur /* For each db allocate a page and map it to the DB dataptr. */ 103c8349639SHoratiu Vultur for (j = 0; j < FDMA_RX_DCB_MAX_DBS; ++j) { 104c8349639SHoratiu Vultur db = &dcb->db[j]; 105c8349639SHoratiu Vultur page = lan966x_fdma_rx_alloc_page(rx, db); 106c8349639SHoratiu Vultur if (!page) 107c8349639SHoratiu Vultur return -ENOMEM; 108c8349639SHoratiu Vultur 109c8349639SHoratiu Vultur db->status = 0; 110c8349639SHoratiu Vultur rx->page[i][j] = page; 111c8349639SHoratiu Vultur } 112c8349639SHoratiu Vultur 113c8349639SHoratiu Vultur lan966x_fdma_rx_add_dcb(rx, dcb, rx->dma + sizeof(*dcb) * i); 114c8349639SHoratiu Vultur } 115c8349639SHoratiu Vultur 116c8349639SHoratiu Vultur return 0; 117c8349639SHoratiu Vultur } 118c8349639SHoratiu Vultur 119c8349639SHoratiu Vultur static void lan966x_fdma_rx_free(struct lan966x_rx *rx) 120c8349639SHoratiu Vultur { 121c8349639SHoratiu Vultur struct lan966x *lan966x = rx->lan966x; 122c8349639SHoratiu Vultur u32 size; 123c8349639SHoratiu Vultur 124c8349639SHoratiu Vultur /* Now it is possible to do the cleanup of dcb */ 125c8349639SHoratiu Vultur size = sizeof(struct lan966x_tx_dcb) * FDMA_DCB_MAX; 126c8349639SHoratiu Vultur size = ALIGN(size, PAGE_SIZE); 127c8349639SHoratiu Vultur dma_free_coherent(lan966x->dev, size, rx->dcbs, rx->dma); 128c8349639SHoratiu Vultur } 129c8349639SHoratiu Vultur 130c8349639SHoratiu Vultur static void lan966x_fdma_rx_start(struct lan966x_rx *rx) 131c8349639SHoratiu Vultur { 132c8349639SHoratiu Vultur struct lan966x *lan966x = rx->lan966x; 133c8349639SHoratiu Vultur u32 mask; 134c8349639SHoratiu Vultur 135c8349639SHoratiu Vultur /* When activating a channel, first is required to write the first DCB 136c8349639SHoratiu Vultur * address and then to activate it 137c8349639SHoratiu Vultur */ 138c8349639SHoratiu Vultur lan_wr(lower_32_bits((u64)rx->dma), lan966x, 139c8349639SHoratiu Vultur FDMA_DCB_LLP(rx->channel_id)); 140c8349639SHoratiu Vultur lan_wr(upper_32_bits((u64)rx->dma), lan966x, 141c8349639SHoratiu Vultur FDMA_DCB_LLP1(rx->channel_id)); 142c8349639SHoratiu Vultur 143c8349639SHoratiu Vultur lan_wr(FDMA_CH_CFG_CH_DCB_DB_CNT_SET(FDMA_RX_DCB_MAX_DBS) | 144c8349639SHoratiu Vultur FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY_SET(1) | 145c8349639SHoratiu Vultur FDMA_CH_CFG_CH_INJ_PORT_SET(0) | 146c8349639SHoratiu Vultur FDMA_CH_CFG_CH_MEM_SET(1), 147c8349639SHoratiu Vultur lan966x, FDMA_CH_CFG(rx->channel_id)); 148c8349639SHoratiu Vultur 149c8349639SHoratiu Vultur /* Start fdma */ 150c8349639SHoratiu Vultur lan_rmw(FDMA_PORT_CTRL_XTR_STOP_SET(0), 151c8349639SHoratiu Vultur FDMA_PORT_CTRL_XTR_STOP, 152c8349639SHoratiu Vultur lan966x, FDMA_PORT_CTRL(0)); 153c8349639SHoratiu Vultur 154c8349639SHoratiu Vultur /* Enable interrupts */ 155c8349639SHoratiu Vultur mask = lan_rd(lan966x, FDMA_INTR_DB_ENA); 156c8349639SHoratiu Vultur mask = FDMA_INTR_DB_ENA_INTR_DB_ENA_GET(mask); 157c8349639SHoratiu Vultur mask |= BIT(rx->channel_id); 158c8349639SHoratiu Vultur lan_rmw(FDMA_INTR_DB_ENA_INTR_DB_ENA_SET(mask), 159c8349639SHoratiu Vultur FDMA_INTR_DB_ENA_INTR_DB_ENA, 160c8349639SHoratiu Vultur lan966x, FDMA_INTR_DB_ENA); 161c8349639SHoratiu Vultur 162c8349639SHoratiu Vultur /* Activate the channel */ 163c8349639SHoratiu Vultur lan_rmw(FDMA_CH_ACTIVATE_CH_ACTIVATE_SET(BIT(rx->channel_id)), 164c8349639SHoratiu Vultur FDMA_CH_ACTIVATE_CH_ACTIVATE, 165c8349639SHoratiu Vultur lan966x, FDMA_CH_ACTIVATE); 166c8349639SHoratiu Vultur } 167c8349639SHoratiu Vultur 168c8349639SHoratiu Vultur static void lan966x_fdma_rx_disable(struct lan966x_rx *rx) 169c8349639SHoratiu Vultur { 170c8349639SHoratiu Vultur struct lan966x *lan966x = rx->lan966x; 171c8349639SHoratiu Vultur u32 val; 172c8349639SHoratiu Vultur 173c8349639SHoratiu Vultur /* Disable the channel */ 174c8349639SHoratiu Vultur lan_rmw(FDMA_CH_DISABLE_CH_DISABLE_SET(BIT(rx->channel_id)), 175c8349639SHoratiu Vultur FDMA_CH_DISABLE_CH_DISABLE, 176c8349639SHoratiu Vultur lan966x, FDMA_CH_DISABLE); 177c8349639SHoratiu Vultur 178c8349639SHoratiu Vultur readx_poll_timeout_atomic(lan966x_fdma_channel_active, lan966x, 179c8349639SHoratiu Vultur val, !(val & BIT(rx->channel_id)), 180c8349639SHoratiu Vultur READL_SLEEP_US, READL_TIMEOUT_US); 181c8349639SHoratiu Vultur 182c8349639SHoratiu Vultur lan_rmw(FDMA_CH_DB_DISCARD_DB_DISCARD_SET(BIT(rx->channel_id)), 183c8349639SHoratiu Vultur FDMA_CH_DB_DISCARD_DB_DISCARD, 184c8349639SHoratiu Vultur lan966x, FDMA_CH_DB_DISCARD); 185c8349639SHoratiu Vultur } 186c8349639SHoratiu Vultur 187c8349639SHoratiu Vultur static void lan966x_fdma_rx_reload(struct lan966x_rx *rx) 188c8349639SHoratiu Vultur { 189c8349639SHoratiu Vultur struct lan966x *lan966x = rx->lan966x; 190c8349639SHoratiu Vultur 191c8349639SHoratiu Vultur lan_rmw(FDMA_CH_RELOAD_CH_RELOAD_SET(BIT(rx->channel_id)), 192c8349639SHoratiu Vultur FDMA_CH_RELOAD_CH_RELOAD, 193c8349639SHoratiu Vultur lan966x, FDMA_CH_RELOAD); 194c8349639SHoratiu Vultur } 195c8349639SHoratiu Vultur 196c8349639SHoratiu Vultur static void lan966x_fdma_tx_add_dcb(struct lan966x_tx *tx, 197c8349639SHoratiu Vultur struct lan966x_tx_dcb *dcb) 198c8349639SHoratiu Vultur { 199c8349639SHoratiu Vultur dcb->nextptr = FDMA_DCB_INVALID_DATA; 200c8349639SHoratiu Vultur dcb->info = 0; 201c8349639SHoratiu Vultur } 202c8349639SHoratiu Vultur 203c8349639SHoratiu Vultur static int lan966x_fdma_tx_alloc(struct lan966x_tx *tx) 204c8349639SHoratiu Vultur { 205c8349639SHoratiu Vultur struct lan966x *lan966x = tx->lan966x; 206c8349639SHoratiu Vultur struct lan966x_tx_dcb *dcb; 207c8349639SHoratiu Vultur struct lan966x_db *db; 208c8349639SHoratiu Vultur int size; 209c8349639SHoratiu Vultur int i, j; 210c8349639SHoratiu Vultur 211c8349639SHoratiu Vultur tx->dcbs_buf = kcalloc(FDMA_DCB_MAX, sizeof(struct lan966x_tx_dcb_buf), 212c8349639SHoratiu Vultur GFP_KERNEL); 213c8349639SHoratiu Vultur if (!tx->dcbs_buf) 214c8349639SHoratiu Vultur return -ENOMEM; 215c8349639SHoratiu Vultur 216c8349639SHoratiu Vultur /* calculate how many pages are needed to allocate the dcbs */ 217c8349639SHoratiu Vultur size = sizeof(struct lan966x_tx_dcb) * FDMA_DCB_MAX; 218c8349639SHoratiu Vultur size = ALIGN(size, PAGE_SIZE); 219c8349639SHoratiu Vultur tx->dcbs = dma_alloc_coherent(lan966x->dev, size, &tx->dma, GFP_KERNEL); 220c8349639SHoratiu Vultur if (!tx->dcbs) 221c8349639SHoratiu Vultur goto out; 222c8349639SHoratiu Vultur 223c8349639SHoratiu Vultur /* Now for each dcb allocate the db */ 224c8349639SHoratiu Vultur for (i = 0; i < FDMA_DCB_MAX; ++i) { 225c8349639SHoratiu Vultur dcb = &tx->dcbs[i]; 226c8349639SHoratiu Vultur 227c8349639SHoratiu Vultur for (j = 0; j < FDMA_TX_DCB_MAX_DBS; ++j) { 228c8349639SHoratiu Vultur db = &dcb->db[j]; 229c8349639SHoratiu Vultur db->dataptr = 0; 230c8349639SHoratiu Vultur db->status = 0; 231c8349639SHoratiu Vultur } 232c8349639SHoratiu Vultur 233c8349639SHoratiu Vultur lan966x_fdma_tx_add_dcb(tx, dcb); 234c8349639SHoratiu Vultur } 235c8349639SHoratiu Vultur 236c8349639SHoratiu Vultur return 0; 237c8349639SHoratiu Vultur 238c8349639SHoratiu Vultur out: 239c8349639SHoratiu Vultur kfree(tx->dcbs_buf); 240c8349639SHoratiu Vultur return -ENOMEM; 241c8349639SHoratiu Vultur } 242c8349639SHoratiu Vultur 243c8349639SHoratiu Vultur static void lan966x_fdma_tx_free(struct lan966x_tx *tx) 244c8349639SHoratiu Vultur { 245c8349639SHoratiu Vultur struct lan966x *lan966x = tx->lan966x; 246c8349639SHoratiu Vultur int size; 247c8349639SHoratiu Vultur 248c8349639SHoratiu Vultur kfree(tx->dcbs_buf); 249c8349639SHoratiu Vultur 250c8349639SHoratiu Vultur size = sizeof(struct lan966x_tx_dcb) * FDMA_DCB_MAX; 251c8349639SHoratiu Vultur size = ALIGN(size, PAGE_SIZE); 252c8349639SHoratiu Vultur dma_free_coherent(lan966x->dev, size, tx->dcbs, tx->dma); 253c8349639SHoratiu Vultur } 254c8349639SHoratiu Vultur 255c8349639SHoratiu Vultur static void lan966x_fdma_tx_activate(struct lan966x_tx *tx) 256c8349639SHoratiu Vultur { 257c8349639SHoratiu Vultur struct lan966x *lan966x = tx->lan966x; 258c8349639SHoratiu Vultur u32 mask; 259c8349639SHoratiu Vultur 260c8349639SHoratiu Vultur /* When activating a channel, first is required to write the first DCB 261c8349639SHoratiu Vultur * address and then to activate it 262c8349639SHoratiu Vultur */ 263c8349639SHoratiu Vultur lan_wr(lower_32_bits((u64)tx->dma), lan966x, 264c8349639SHoratiu Vultur FDMA_DCB_LLP(tx->channel_id)); 265c8349639SHoratiu Vultur lan_wr(upper_32_bits((u64)tx->dma), lan966x, 266c8349639SHoratiu Vultur FDMA_DCB_LLP1(tx->channel_id)); 267c8349639SHoratiu Vultur 268c8349639SHoratiu Vultur lan_wr(FDMA_CH_CFG_CH_DCB_DB_CNT_SET(FDMA_TX_DCB_MAX_DBS) | 269c8349639SHoratiu Vultur FDMA_CH_CFG_CH_INTR_DB_EOF_ONLY_SET(1) | 270c8349639SHoratiu Vultur FDMA_CH_CFG_CH_INJ_PORT_SET(0) | 271c8349639SHoratiu Vultur FDMA_CH_CFG_CH_MEM_SET(1), 272c8349639SHoratiu Vultur lan966x, FDMA_CH_CFG(tx->channel_id)); 273c8349639SHoratiu Vultur 274c8349639SHoratiu Vultur /* Start fdma */ 275c8349639SHoratiu Vultur lan_rmw(FDMA_PORT_CTRL_INJ_STOP_SET(0), 276c8349639SHoratiu Vultur FDMA_PORT_CTRL_INJ_STOP, 277c8349639SHoratiu Vultur lan966x, FDMA_PORT_CTRL(0)); 278c8349639SHoratiu Vultur 279c8349639SHoratiu Vultur /* Enable interrupts */ 280c8349639SHoratiu Vultur mask = lan_rd(lan966x, FDMA_INTR_DB_ENA); 281c8349639SHoratiu Vultur mask = FDMA_INTR_DB_ENA_INTR_DB_ENA_GET(mask); 282c8349639SHoratiu Vultur mask |= BIT(tx->channel_id); 283c8349639SHoratiu Vultur lan_rmw(FDMA_INTR_DB_ENA_INTR_DB_ENA_SET(mask), 284c8349639SHoratiu Vultur FDMA_INTR_DB_ENA_INTR_DB_ENA, 285c8349639SHoratiu Vultur lan966x, FDMA_INTR_DB_ENA); 286c8349639SHoratiu Vultur 287c8349639SHoratiu Vultur /* Activate the channel */ 288c8349639SHoratiu Vultur lan_rmw(FDMA_CH_ACTIVATE_CH_ACTIVATE_SET(BIT(tx->channel_id)), 289c8349639SHoratiu Vultur FDMA_CH_ACTIVATE_CH_ACTIVATE, 290c8349639SHoratiu Vultur lan966x, FDMA_CH_ACTIVATE); 291c8349639SHoratiu Vultur } 292c8349639SHoratiu Vultur 293c8349639SHoratiu Vultur static void lan966x_fdma_tx_disable(struct lan966x_tx *tx) 294c8349639SHoratiu Vultur { 295c8349639SHoratiu Vultur struct lan966x *lan966x = tx->lan966x; 296c8349639SHoratiu Vultur u32 val; 297c8349639SHoratiu Vultur 298c8349639SHoratiu Vultur /* Disable the channel */ 299c8349639SHoratiu Vultur lan_rmw(FDMA_CH_DISABLE_CH_DISABLE_SET(BIT(tx->channel_id)), 300c8349639SHoratiu Vultur FDMA_CH_DISABLE_CH_DISABLE, 301c8349639SHoratiu Vultur lan966x, FDMA_CH_DISABLE); 302c8349639SHoratiu Vultur 303c8349639SHoratiu Vultur readx_poll_timeout_atomic(lan966x_fdma_channel_active, lan966x, 304c8349639SHoratiu Vultur val, !(val & BIT(tx->channel_id)), 305c8349639SHoratiu Vultur READL_SLEEP_US, READL_TIMEOUT_US); 306c8349639SHoratiu Vultur 307c8349639SHoratiu Vultur lan_rmw(FDMA_CH_DB_DISCARD_DB_DISCARD_SET(BIT(tx->channel_id)), 308c8349639SHoratiu Vultur FDMA_CH_DB_DISCARD_DB_DISCARD, 309c8349639SHoratiu Vultur lan966x, FDMA_CH_DB_DISCARD); 310c8349639SHoratiu Vultur 311c8349639SHoratiu Vultur tx->activated = false; 312c8349639SHoratiu Vultur } 313c8349639SHoratiu Vultur 314c8349639SHoratiu Vultur static void lan966x_fdma_tx_reload(struct lan966x_tx *tx) 315c8349639SHoratiu Vultur { 316c8349639SHoratiu Vultur struct lan966x *lan966x = tx->lan966x; 317c8349639SHoratiu Vultur 318c8349639SHoratiu Vultur /* Write the registers to reload the channel */ 319c8349639SHoratiu Vultur lan_rmw(FDMA_CH_RELOAD_CH_RELOAD_SET(BIT(tx->channel_id)), 320c8349639SHoratiu Vultur FDMA_CH_RELOAD_CH_RELOAD, 321c8349639SHoratiu Vultur lan966x, FDMA_CH_RELOAD); 322c8349639SHoratiu Vultur } 323c8349639SHoratiu Vultur 324c8349639SHoratiu Vultur static void lan966x_fdma_wakeup_netdev(struct lan966x *lan966x) 325c8349639SHoratiu Vultur { 326c8349639SHoratiu Vultur struct lan966x_port *port; 327c8349639SHoratiu Vultur int i; 328c8349639SHoratiu Vultur 329c8349639SHoratiu Vultur for (i = 0; i < lan966x->num_phys_ports; ++i) { 330c8349639SHoratiu Vultur port = lan966x->ports[i]; 331c8349639SHoratiu Vultur if (!port) 332c8349639SHoratiu Vultur continue; 333c8349639SHoratiu Vultur 334c8349639SHoratiu Vultur if (netif_queue_stopped(port->dev)) 335c8349639SHoratiu Vultur netif_wake_queue(port->dev); 336c8349639SHoratiu Vultur } 337c8349639SHoratiu Vultur } 338c8349639SHoratiu Vultur 339*2ea1cbacSHoratiu Vultur static void lan966x_fdma_stop_netdev(struct lan966x *lan966x) 340*2ea1cbacSHoratiu Vultur { 341*2ea1cbacSHoratiu Vultur struct lan966x_port *port; 342*2ea1cbacSHoratiu Vultur int i; 343*2ea1cbacSHoratiu Vultur 344*2ea1cbacSHoratiu Vultur for (i = 0; i < lan966x->num_phys_ports; ++i) { 345*2ea1cbacSHoratiu Vultur port = lan966x->ports[i]; 346*2ea1cbacSHoratiu Vultur if (!port) 347*2ea1cbacSHoratiu Vultur continue; 348*2ea1cbacSHoratiu Vultur 349*2ea1cbacSHoratiu Vultur netif_stop_queue(port->dev); 350*2ea1cbacSHoratiu Vultur } 351*2ea1cbacSHoratiu Vultur } 352*2ea1cbacSHoratiu Vultur 353c8349639SHoratiu Vultur static void lan966x_fdma_tx_clear_buf(struct lan966x *lan966x, int weight) 354c8349639SHoratiu Vultur { 355c8349639SHoratiu Vultur struct lan966x_tx *tx = &lan966x->tx; 356c8349639SHoratiu Vultur struct lan966x_tx_dcb_buf *dcb_buf; 357c8349639SHoratiu Vultur struct lan966x_db *db; 358c8349639SHoratiu Vultur unsigned long flags; 359c8349639SHoratiu Vultur bool clear = false; 360c8349639SHoratiu Vultur int i; 361c8349639SHoratiu Vultur 362c8349639SHoratiu Vultur spin_lock_irqsave(&lan966x->tx_lock, flags); 363c8349639SHoratiu Vultur for (i = 0; i < FDMA_DCB_MAX; ++i) { 364c8349639SHoratiu Vultur dcb_buf = &tx->dcbs_buf[i]; 365c8349639SHoratiu Vultur 366c8349639SHoratiu Vultur if (!dcb_buf->used) 367c8349639SHoratiu Vultur continue; 368c8349639SHoratiu Vultur 369c8349639SHoratiu Vultur db = &tx->dcbs[i].db[0]; 370c8349639SHoratiu Vultur if (!(db->status & FDMA_DCB_STATUS_DONE)) 371c8349639SHoratiu Vultur continue; 372c8349639SHoratiu Vultur 373c8349639SHoratiu Vultur dcb_buf->dev->stats.tx_packets++; 374c8349639SHoratiu Vultur dcb_buf->dev->stats.tx_bytes += dcb_buf->skb->len; 375c8349639SHoratiu Vultur 376c8349639SHoratiu Vultur dcb_buf->used = false; 377c8349639SHoratiu Vultur dma_unmap_single(lan966x->dev, 378c8349639SHoratiu Vultur dcb_buf->dma_addr, 379c8349639SHoratiu Vultur dcb_buf->skb->len, 380c8349639SHoratiu Vultur DMA_TO_DEVICE); 381c8349639SHoratiu Vultur if (!dcb_buf->ptp) 382c8349639SHoratiu Vultur dev_kfree_skb_any(dcb_buf->skb); 383c8349639SHoratiu Vultur 384c8349639SHoratiu Vultur clear = true; 385c8349639SHoratiu Vultur } 386c8349639SHoratiu Vultur 387c8349639SHoratiu Vultur if (clear) 388c8349639SHoratiu Vultur lan966x_fdma_wakeup_netdev(lan966x); 389c8349639SHoratiu Vultur 390c8349639SHoratiu Vultur spin_unlock_irqrestore(&lan966x->tx_lock, flags); 391c8349639SHoratiu Vultur } 392c8349639SHoratiu Vultur 393c8349639SHoratiu Vultur static bool lan966x_fdma_rx_more_frames(struct lan966x_rx *rx) 394c8349639SHoratiu Vultur { 395c8349639SHoratiu Vultur struct lan966x_db *db; 396c8349639SHoratiu Vultur 397c8349639SHoratiu Vultur /* Check if there is any data */ 398c8349639SHoratiu Vultur db = &rx->dcbs[rx->dcb_index].db[rx->db_index]; 399c8349639SHoratiu Vultur if (unlikely(!(db->status & FDMA_DCB_STATUS_DONE))) 400c8349639SHoratiu Vultur return false; 401c8349639SHoratiu Vultur 402c8349639SHoratiu Vultur return true; 403c8349639SHoratiu Vultur } 404c8349639SHoratiu Vultur 405c8349639SHoratiu Vultur static struct sk_buff *lan966x_fdma_rx_get_frame(struct lan966x_rx *rx) 406c8349639SHoratiu Vultur { 407c8349639SHoratiu Vultur struct lan966x *lan966x = rx->lan966x; 408c8349639SHoratiu Vultur u64 src_port, timestamp; 409c8349639SHoratiu Vultur struct lan966x_db *db; 410c8349639SHoratiu Vultur struct sk_buff *skb; 411c8349639SHoratiu Vultur struct page *page; 412c8349639SHoratiu Vultur 413c8349639SHoratiu Vultur /* Get the received frame and unmap it */ 414c8349639SHoratiu Vultur db = &rx->dcbs[rx->dcb_index].db[rx->db_index]; 415c8349639SHoratiu Vultur page = rx->page[rx->dcb_index][rx->db_index]; 416c8349639SHoratiu Vultur skb = build_skb(page_address(page), PAGE_SIZE << rx->page_order); 417c8349639SHoratiu Vultur if (unlikely(!skb)) 418c8349639SHoratiu Vultur goto unmap_page; 419c8349639SHoratiu Vultur 420c8349639SHoratiu Vultur dma_unmap_single(lan966x->dev, (dma_addr_t)db->dataptr, 421c8349639SHoratiu Vultur FDMA_DCB_STATUS_BLOCKL(db->status), 422c8349639SHoratiu Vultur DMA_FROM_DEVICE); 423c8349639SHoratiu Vultur skb_put(skb, FDMA_DCB_STATUS_BLOCKL(db->status)); 424c8349639SHoratiu Vultur 425c8349639SHoratiu Vultur lan966x_ifh_get_src_port(skb->data, &src_port); 426c8349639SHoratiu Vultur lan966x_ifh_get_timestamp(skb->data, ×tamp); 427c8349639SHoratiu Vultur 428c8349639SHoratiu Vultur WARN_ON(src_port >= lan966x->num_phys_ports); 429c8349639SHoratiu Vultur 430c8349639SHoratiu Vultur skb->dev = lan966x->ports[src_port]->dev; 431c8349639SHoratiu Vultur skb_pull(skb, IFH_LEN * sizeof(u32)); 432c8349639SHoratiu Vultur 433c8349639SHoratiu Vultur if (likely(!(skb->dev->features & NETIF_F_RXFCS))) 434c8349639SHoratiu Vultur skb_trim(skb, skb->len - ETH_FCS_LEN); 435c8349639SHoratiu Vultur 436c8349639SHoratiu Vultur lan966x_ptp_rxtstamp(lan966x, skb, timestamp); 437c8349639SHoratiu Vultur skb->protocol = eth_type_trans(skb, skb->dev); 438c8349639SHoratiu Vultur 439c8349639SHoratiu Vultur if (lan966x->bridge_mask & BIT(src_port)) { 440c8349639SHoratiu Vultur skb->offload_fwd_mark = 1; 441c8349639SHoratiu Vultur 442c8349639SHoratiu Vultur skb_reset_network_header(skb); 443c8349639SHoratiu Vultur if (!lan966x_hw_offload(lan966x, src_port, skb)) 444c8349639SHoratiu Vultur skb->offload_fwd_mark = 0; 445c8349639SHoratiu Vultur } 446c8349639SHoratiu Vultur 447c8349639SHoratiu Vultur skb->dev->stats.rx_bytes += skb->len; 448c8349639SHoratiu Vultur skb->dev->stats.rx_packets++; 449c8349639SHoratiu Vultur 450c8349639SHoratiu Vultur return skb; 451c8349639SHoratiu Vultur 452c8349639SHoratiu Vultur unmap_page: 453c8349639SHoratiu Vultur dma_unmap_page(lan966x->dev, (dma_addr_t)db->dataptr, 454c8349639SHoratiu Vultur FDMA_DCB_STATUS_BLOCKL(db->status), 455c8349639SHoratiu Vultur DMA_FROM_DEVICE); 456c8349639SHoratiu Vultur __free_pages(page, rx->page_order); 457c8349639SHoratiu Vultur 458c8349639SHoratiu Vultur return NULL; 459c8349639SHoratiu Vultur } 460c8349639SHoratiu Vultur 461c8349639SHoratiu Vultur static int lan966x_fdma_napi_poll(struct napi_struct *napi, int weight) 462c8349639SHoratiu Vultur { 463c8349639SHoratiu Vultur struct lan966x *lan966x = container_of(napi, struct lan966x, napi); 464c8349639SHoratiu Vultur struct lan966x_rx *rx = &lan966x->rx; 465c8349639SHoratiu Vultur int dcb_reload = rx->dcb_index; 466c8349639SHoratiu Vultur struct lan966x_rx_dcb *old_dcb; 467c8349639SHoratiu Vultur struct lan966x_db *db; 468c8349639SHoratiu Vultur struct sk_buff *skb; 469c8349639SHoratiu Vultur struct page *page; 470c8349639SHoratiu Vultur int counter = 0; 471c8349639SHoratiu Vultur u64 nextptr; 472c8349639SHoratiu Vultur 473c8349639SHoratiu Vultur lan966x_fdma_tx_clear_buf(lan966x, weight); 474c8349639SHoratiu Vultur 475c8349639SHoratiu Vultur /* Get all received skb */ 476c8349639SHoratiu Vultur while (counter < weight) { 477c8349639SHoratiu Vultur if (!lan966x_fdma_rx_more_frames(rx)) 478c8349639SHoratiu Vultur break; 479c8349639SHoratiu Vultur 480c8349639SHoratiu Vultur skb = lan966x_fdma_rx_get_frame(rx); 481c8349639SHoratiu Vultur 482c8349639SHoratiu Vultur rx->page[rx->dcb_index][rx->db_index] = NULL; 483c8349639SHoratiu Vultur rx->dcb_index++; 484c8349639SHoratiu Vultur rx->dcb_index &= FDMA_DCB_MAX - 1; 485c8349639SHoratiu Vultur 486c8349639SHoratiu Vultur if (!skb) 487c8349639SHoratiu Vultur break; 488c8349639SHoratiu Vultur 489c8349639SHoratiu Vultur napi_gro_receive(&lan966x->napi, skb); 490c8349639SHoratiu Vultur counter++; 491c8349639SHoratiu Vultur } 492c8349639SHoratiu Vultur 493c8349639SHoratiu Vultur /* Allocate new pages and map them */ 494c8349639SHoratiu Vultur while (dcb_reload != rx->dcb_index) { 495c8349639SHoratiu Vultur db = &rx->dcbs[dcb_reload].db[rx->db_index]; 496c8349639SHoratiu Vultur page = lan966x_fdma_rx_alloc_page(rx, db); 497c8349639SHoratiu Vultur if (unlikely(!page)) 498c8349639SHoratiu Vultur break; 499c8349639SHoratiu Vultur rx->page[dcb_reload][rx->db_index] = page; 500c8349639SHoratiu Vultur 501c8349639SHoratiu Vultur old_dcb = &rx->dcbs[dcb_reload]; 502c8349639SHoratiu Vultur dcb_reload++; 503c8349639SHoratiu Vultur dcb_reload &= FDMA_DCB_MAX - 1; 504c8349639SHoratiu Vultur 505c8349639SHoratiu Vultur nextptr = rx->dma + ((unsigned long)old_dcb - 506c8349639SHoratiu Vultur (unsigned long)rx->dcbs); 507c8349639SHoratiu Vultur lan966x_fdma_rx_add_dcb(rx, old_dcb, nextptr); 508c8349639SHoratiu Vultur lan966x_fdma_rx_reload(rx); 509c8349639SHoratiu Vultur } 510c8349639SHoratiu Vultur 511c8349639SHoratiu Vultur if (counter < weight && napi_complete_done(napi, counter)) 512c8349639SHoratiu Vultur lan_wr(0xff, lan966x, FDMA_INTR_DB_ENA); 513c8349639SHoratiu Vultur 514c8349639SHoratiu Vultur return counter; 515c8349639SHoratiu Vultur } 516c8349639SHoratiu Vultur 517c8349639SHoratiu Vultur irqreturn_t lan966x_fdma_irq_handler(int irq, void *args) 518c8349639SHoratiu Vultur { 519c8349639SHoratiu Vultur struct lan966x *lan966x = args; 520c8349639SHoratiu Vultur u32 db, err, err_type; 521c8349639SHoratiu Vultur 522c8349639SHoratiu Vultur db = lan_rd(lan966x, FDMA_INTR_DB); 523c8349639SHoratiu Vultur err = lan_rd(lan966x, FDMA_INTR_ERR); 524c8349639SHoratiu Vultur 525c8349639SHoratiu Vultur if (db) { 526c8349639SHoratiu Vultur lan_wr(0, lan966x, FDMA_INTR_DB_ENA); 527c8349639SHoratiu Vultur lan_wr(db, lan966x, FDMA_INTR_DB); 528c8349639SHoratiu Vultur 529c8349639SHoratiu Vultur napi_schedule(&lan966x->napi); 530c8349639SHoratiu Vultur } 531c8349639SHoratiu Vultur 532c8349639SHoratiu Vultur if (err) { 533c8349639SHoratiu Vultur err_type = lan_rd(lan966x, FDMA_ERRORS); 534c8349639SHoratiu Vultur 535c8349639SHoratiu Vultur WARN(1, "Unexpected error: %d, error_type: %d\n", err, err_type); 536c8349639SHoratiu Vultur 537c8349639SHoratiu Vultur lan_wr(err, lan966x, FDMA_INTR_ERR); 538c8349639SHoratiu Vultur lan_wr(err_type, lan966x, FDMA_ERRORS); 539c8349639SHoratiu Vultur } 540c8349639SHoratiu Vultur 541c8349639SHoratiu Vultur return IRQ_HANDLED; 542c8349639SHoratiu Vultur } 543c8349639SHoratiu Vultur 544c8349639SHoratiu Vultur static int lan966x_fdma_get_next_dcb(struct lan966x_tx *tx) 545c8349639SHoratiu Vultur { 546c8349639SHoratiu Vultur struct lan966x_tx_dcb_buf *dcb_buf; 547c8349639SHoratiu Vultur int i; 548c8349639SHoratiu Vultur 549c8349639SHoratiu Vultur for (i = 0; i < FDMA_DCB_MAX; ++i) { 550c8349639SHoratiu Vultur dcb_buf = &tx->dcbs_buf[i]; 551c8349639SHoratiu Vultur if (!dcb_buf->used && i != tx->last_in_use) 552c8349639SHoratiu Vultur return i; 553c8349639SHoratiu Vultur } 554c8349639SHoratiu Vultur 555c8349639SHoratiu Vultur return -1; 556c8349639SHoratiu Vultur } 557c8349639SHoratiu Vultur 558c8349639SHoratiu Vultur int lan966x_fdma_xmit(struct sk_buff *skb, __be32 *ifh, struct net_device *dev) 559c8349639SHoratiu Vultur { 560c8349639SHoratiu Vultur struct lan966x_port *port = netdev_priv(dev); 561c8349639SHoratiu Vultur struct lan966x *lan966x = port->lan966x; 562c8349639SHoratiu Vultur struct lan966x_tx_dcb_buf *next_dcb_buf; 563c8349639SHoratiu Vultur struct lan966x_tx_dcb *next_dcb, *dcb; 564c8349639SHoratiu Vultur struct lan966x_tx *tx = &lan966x->tx; 565c8349639SHoratiu Vultur struct lan966x_db *next_db; 566c8349639SHoratiu Vultur int needed_headroom; 567c8349639SHoratiu Vultur int needed_tailroom; 568c8349639SHoratiu Vultur dma_addr_t dma_addr; 569c8349639SHoratiu Vultur int next_to_use; 570c8349639SHoratiu Vultur int err; 571c8349639SHoratiu Vultur 572c8349639SHoratiu Vultur /* Get next index */ 573c8349639SHoratiu Vultur next_to_use = lan966x_fdma_get_next_dcb(tx); 574c8349639SHoratiu Vultur if (next_to_use < 0) { 575c8349639SHoratiu Vultur netif_stop_queue(dev); 576c8349639SHoratiu Vultur return NETDEV_TX_BUSY; 577c8349639SHoratiu Vultur } 578c8349639SHoratiu Vultur 579c8349639SHoratiu Vultur if (skb_put_padto(skb, ETH_ZLEN)) { 580c8349639SHoratiu Vultur dev->stats.tx_dropped++; 581c8349639SHoratiu Vultur return NETDEV_TX_OK; 582c8349639SHoratiu Vultur } 583c8349639SHoratiu Vultur 584c8349639SHoratiu Vultur /* skb processing */ 585c8349639SHoratiu Vultur needed_headroom = max_t(int, IFH_LEN * sizeof(u32) - skb_headroom(skb), 0); 586c8349639SHoratiu Vultur needed_tailroom = max_t(int, ETH_FCS_LEN - skb_tailroom(skb), 0); 587c8349639SHoratiu Vultur if (needed_headroom || needed_tailroom || skb_header_cloned(skb)) { 588c8349639SHoratiu Vultur err = pskb_expand_head(skb, needed_headroom, needed_tailroom, 589c8349639SHoratiu Vultur GFP_ATOMIC); 590c8349639SHoratiu Vultur if (unlikely(err)) { 591c8349639SHoratiu Vultur dev->stats.tx_dropped++; 592c8349639SHoratiu Vultur err = NETDEV_TX_OK; 593c8349639SHoratiu Vultur goto release; 594c8349639SHoratiu Vultur } 595c8349639SHoratiu Vultur } 596c8349639SHoratiu Vultur 597c8349639SHoratiu Vultur skb_tx_timestamp(skb); 598c8349639SHoratiu Vultur skb_push(skb, IFH_LEN * sizeof(u32)); 599c8349639SHoratiu Vultur memcpy(skb->data, ifh, IFH_LEN * sizeof(u32)); 600c8349639SHoratiu Vultur skb_put(skb, 4); 601c8349639SHoratiu Vultur 602c8349639SHoratiu Vultur dma_addr = dma_map_single(lan966x->dev, skb->data, skb->len, 603c8349639SHoratiu Vultur DMA_TO_DEVICE); 604c8349639SHoratiu Vultur if (dma_mapping_error(lan966x->dev, dma_addr)) { 605c8349639SHoratiu Vultur dev->stats.tx_dropped++; 606c8349639SHoratiu Vultur err = NETDEV_TX_OK; 607c8349639SHoratiu Vultur goto release; 608c8349639SHoratiu Vultur } 609c8349639SHoratiu Vultur 610c8349639SHoratiu Vultur /* Setup next dcb */ 611c8349639SHoratiu Vultur next_dcb = &tx->dcbs[next_to_use]; 612c8349639SHoratiu Vultur next_dcb->nextptr = FDMA_DCB_INVALID_DATA; 613c8349639SHoratiu Vultur 614c8349639SHoratiu Vultur next_db = &next_dcb->db[0]; 615c8349639SHoratiu Vultur next_db->dataptr = dma_addr; 616c8349639SHoratiu Vultur next_db->status = FDMA_DCB_STATUS_SOF | 617c8349639SHoratiu Vultur FDMA_DCB_STATUS_EOF | 618c8349639SHoratiu Vultur FDMA_DCB_STATUS_INTR | 619c8349639SHoratiu Vultur FDMA_DCB_STATUS_BLOCKO(0) | 620c8349639SHoratiu Vultur FDMA_DCB_STATUS_BLOCKL(skb->len); 621c8349639SHoratiu Vultur 622c8349639SHoratiu Vultur /* Fill up the buffer */ 623c8349639SHoratiu Vultur next_dcb_buf = &tx->dcbs_buf[next_to_use]; 624c8349639SHoratiu Vultur next_dcb_buf->skb = skb; 625c8349639SHoratiu Vultur next_dcb_buf->dma_addr = dma_addr; 626c8349639SHoratiu Vultur next_dcb_buf->used = true; 627c8349639SHoratiu Vultur next_dcb_buf->ptp = false; 628c8349639SHoratiu Vultur next_dcb_buf->dev = dev; 629c8349639SHoratiu Vultur 630c8349639SHoratiu Vultur if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && 631c8349639SHoratiu Vultur LAN966X_SKB_CB(skb)->rew_op == IFH_REW_OP_TWO_STEP_PTP) 632c8349639SHoratiu Vultur next_dcb_buf->ptp = true; 633c8349639SHoratiu Vultur 634c8349639SHoratiu Vultur if (likely(lan966x->tx.activated)) { 635c8349639SHoratiu Vultur /* Connect current dcb to the next db */ 636c8349639SHoratiu Vultur dcb = &tx->dcbs[tx->last_in_use]; 637c8349639SHoratiu Vultur dcb->nextptr = tx->dma + (next_to_use * 638c8349639SHoratiu Vultur sizeof(struct lan966x_tx_dcb)); 639c8349639SHoratiu Vultur 640c8349639SHoratiu Vultur lan966x_fdma_tx_reload(tx); 641c8349639SHoratiu Vultur } else { 642c8349639SHoratiu Vultur /* Because it is first time, then just activate */ 643c8349639SHoratiu Vultur lan966x->tx.activated = true; 644c8349639SHoratiu Vultur lan966x_fdma_tx_activate(tx); 645c8349639SHoratiu Vultur } 646c8349639SHoratiu Vultur 647c8349639SHoratiu Vultur /* Move to next dcb because this last in use */ 648c8349639SHoratiu Vultur tx->last_in_use = next_to_use; 649c8349639SHoratiu Vultur 650c8349639SHoratiu Vultur return NETDEV_TX_OK; 651c8349639SHoratiu Vultur 652c8349639SHoratiu Vultur release: 653c8349639SHoratiu Vultur if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && 654c8349639SHoratiu Vultur LAN966X_SKB_CB(skb)->rew_op == IFH_REW_OP_TWO_STEP_PTP) 655c8349639SHoratiu Vultur lan966x_ptp_txtstamp_release(port, skb); 656c8349639SHoratiu Vultur 657c8349639SHoratiu Vultur dev_kfree_skb_any(skb); 658c8349639SHoratiu Vultur return err; 659c8349639SHoratiu Vultur } 660c8349639SHoratiu Vultur 661*2ea1cbacSHoratiu Vultur static int lan966x_fdma_get_max_mtu(struct lan966x *lan966x) 662*2ea1cbacSHoratiu Vultur { 663*2ea1cbacSHoratiu Vultur int max_mtu = 0; 664*2ea1cbacSHoratiu Vultur int i; 665*2ea1cbacSHoratiu Vultur 666*2ea1cbacSHoratiu Vultur for (i = 0; i < lan966x->num_phys_ports; ++i) { 667*2ea1cbacSHoratiu Vultur int mtu; 668*2ea1cbacSHoratiu Vultur 669*2ea1cbacSHoratiu Vultur if (!lan966x->ports[i]) 670*2ea1cbacSHoratiu Vultur continue; 671*2ea1cbacSHoratiu Vultur 672*2ea1cbacSHoratiu Vultur mtu = lan966x->ports[i]->dev->mtu; 673*2ea1cbacSHoratiu Vultur if (mtu > max_mtu) 674*2ea1cbacSHoratiu Vultur max_mtu = mtu; 675*2ea1cbacSHoratiu Vultur } 676*2ea1cbacSHoratiu Vultur 677*2ea1cbacSHoratiu Vultur return max_mtu; 678*2ea1cbacSHoratiu Vultur } 679*2ea1cbacSHoratiu Vultur 680*2ea1cbacSHoratiu Vultur static int lan966x_qsys_sw_status(struct lan966x *lan966x) 681*2ea1cbacSHoratiu Vultur { 682*2ea1cbacSHoratiu Vultur return lan_rd(lan966x, QSYS_SW_STATUS(CPU_PORT)); 683*2ea1cbacSHoratiu Vultur } 684*2ea1cbacSHoratiu Vultur 685*2ea1cbacSHoratiu Vultur static int lan966x_fdma_reload(struct lan966x *lan966x, int new_mtu) 686*2ea1cbacSHoratiu Vultur { 687*2ea1cbacSHoratiu Vultur void *rx_dcbs, *tx_dcbs, *tx_dcbs_buf; 688*2ea1cbacSHoratiu Vultur dma_addr_t rx_dma, tx_dma; 689*2ea1cbacSHoratiu Vultur u32 size; 690*2ea1cbacSHoratiu Vultur int err; 691*2ea1cbacSHoratiu Vultur 692*2ea1cbacSHoratiu Vultur /* Store these for later to free them */ 693*2ea1cbacSHoratiu Vultur rx_dma = lan966x->rx.dma; 694*2ea1cbacSHoratiu Vultur tx_dma = lan966x->tx.dma; 695*2ea1cbacSHoratiu Vultur rx_dcbs = lan966x->rx.dcbs; 696*2ea1cbacSHoratiu Vultur tx_dcbs = lan966x->tx.dcbs; 697*2ea1cbacSHoratiu Vultur tx_dcbs_buf = lan966x->tx.dcbs_buf; 698*2ea1cbacSHoratiu Vultur 699*2ea1cbacSHoratiu Vultur napi_synchronize(&lan966x->napi); 700*2ea1cbacSHoratiu Vultur napi_disable(&lan966x->napi); 701*2ea1cbacSHoratiu Vultur lan966x_fdma_stop_netdev(lan966x); 702*2ea1cbacSHoratiu Vultur 703*2ea1cbacSHoratiu Vultur lan966x_fdma_rx_disable(&lan966x->rx); 704*2ea1cbacSHoratiu Vultur lan966x_fdma_rx_free_pages(&lan966x->rx); 705*2ea1cbacSHoratiu Vultur lan966x->rx.page_order = round_up(new_mtu, PAGE_SIZE) / PAGE_SIZE - 1; 706*2ea1cbacSHoratiu Vultur err = lan966x_fdma_rx_alloc(&lan966x->rx); 707*2ea1cbacSHoratiu Vultur if (err) 708*2ea1cbacSHoratiu Vultur goto restore; 709*2ea1cbacSHoratiu Vultur lan966x_fdma_rx_start(&lan966x->rx); 710*2ea1cbacSHoratiu Vultur 711*2ea1cbacSHoratiu Vultur size = sizeof(struct lan966x_rx_dcb) * FDMA_DCB_MAX; 712*2ea1cbacSHoratiu Vultur size = ALIGN(size, PAGE_SIZE); 713*2ea1cbacSHoratiu Vultur dma_free_coherent(lan966x->dev, size, rx_dcbs, rx_dma); 714*2ea1cbacSHoratiu Vultur 715*2ea1cbacSHoratiu Vultur lan966x_fdma_tx_disable(&lan966x->tx); 716*2ea1cbacSHoratiu Vultur err = lan966x_fdma_tx_alloc(&lan966x->tx); 717*2ea1cbacSHoratiu Vultur if (err) 718*2ea1cbacSHoratiu Vultur goto restore_tx; 719*2ea1cbacSHoratiu Vultur 720*2ea1cbacSHoratiu Vultur size = sizeof(struct lan966x_tx_dcb) * FDMA_DCB_MAX; 721*2ea1cbacSHoratiu Vultur size = ALIGN(size, PAGE_SIZE); 722*2ea1cbacSHoratiu Vultur dma_free_coherent(lan966x->dev, size, tx_dcbs, tx_dma); 723*2ea1cbacSHoratiu Vultur 724*2ea1cbacSHoratiu Vultur kfree(tx_dcbs_buf); 725*2ea1cbacSHoratiu Vultur 726*2ea1cbacSHoratiu Vultur lan966x_fdma_wakeup_netdev(lan966x); 727*2ea1cbacSHoratiu Vultur napi_enable(&lan966x->napi); 728*2ea1cbacSHoratiu Vultur 729*2ea1cbacSHoratiu Vultur return err; 730*2ea1cbacSHoratiu Vultur restore: 731*2ea1cbacSHoratiu Vultur lan966x->rx.dma = rx_dma; 732*2ea1cbacSHoratiu Vultur lan966x->tx.dma = tx_dma; 733*2ea1cbacSHoratiu Vultur lan966x_fdma_rx_start(&lan966x->rx); 734*2ea1cbacSHoratiu Vultur 735*2ea1cbacSHoratiu Vultur restore_tx: 736*2ea1cbacSHoratiu Vultur lan966x->rx.dcbs = rx_dcbs; 737*2ea1cbacSHoratiu Vultur lan966x->tx.dcbs = tx_dcbs; 738*2ea1cbacSHoratiu Vultur lan966x->tx.dcbs_buf = tx_dcbs_buf; 739*2ea1cbacSHoratiu Vultur 740*2ea1cbacSHoratiu Vultur return err; 741*2ea1cbacSHoratiu Vultur } 742*2ea1cbacSHoratiu Vultur 743*2ea1cbacSHoratiu Vultur int lan966x_fdma_change_mtu(struct lan966x *lan966x) 744*2ea1cbacSHoratiu Vultur { 745*2ea1cbacSHoratiu Vultur int max_mtu; 746*2ea1cbacSHoratiu Vultur int err; 747*2ea1cbacSHoratiu Vultur u32 val; 748*2ea1cbacSHoratiu Vultur 749*2ea1cbacSHoratiu Vultur max_mtu = lan966x_fdma_get_max_mtu(lan966x); 750*2ea1cbacSHoratiu Vultur max_mtu += IFH_LEN * sizeof(u32); 751*2ea1cbacSHoratiu Vultur 752*2ea1cbacSHoratiu Vultur if (round_up(max_mtu, PAGE_SIZE) / PAGE_SIZE - 1 == 753*2ea1cbacSHoratiu Vultur lan966x->rx.page_order) 754*2ea1cbacSHoratiu Vultur return 0; 755*2ea1cbacSHoratiu Vultur 756*2ea1cbacSHoratiu Vultur /* Disable the CPU port */ 757*2ea1cbacSHoratiu Vultur lan_rmw(QSYS_SW_PORT_MODE_PORT_ENA_SET(0), 758*2ea1cbacSHoratiu Vultur QSYS_SW_PORT_MODE_PORT_ENA, 759*2ea1cbacSHoratiu Vultur lan966x, QSYS_SW_PORT_MODE(CPU_PORT)); 760*2ea1cbacSHoratiu Vultur 761*2ea1cbacSHoratiu Vultur /* Flush the CPU queues */ 762*2ea1cbacSHoratiu Vultur readx_poll_timeout(lan966x_qsys_sw_status, lan966x, 763*2ea1cbacSHoratiu Vultur val, !(QSYS_SW_STATUS_EQ_AVAIL_GET(val)), 764*2ea1cbacSHoratiu Vultur READL_SLEEP_US, READL_TIMEOUT_US); 765*2ea1cbacSHoratiu Vultur 766*2ea1cbacSHoratiu Vultur /* Add a sleep in case there are frames between the queues and the CPU 767*2ea1cbacSHoratiu Vultur * port 768*2ea1cbacSHoratiu Vultur */ 769*2ea1cbacSHoratiu Vultur usleep_range(1000, 2000); 770*2ea1cbacSHoratiu Vultur 771*2ea1cbacSHoratiu Vultur err = lan966x_fdma_reload(lan966x, max_mtu); 772*2ea1cbacSHoratiu Vultur 773*2ea1cbacSHoratiu Vultur /* Enable back the CPU port */ 774*2ea1cbacSHoratiu Vultur lan_rmw(QSYS_SW_PORT_MODE_PORT_ENA_SET(1), 775*2ea1cbacSHoratiu Vultur QSYS_SW_PORT_MODE_PORT_ENA, 776*2ea1cbacSHoratiu Vultur lan966x, QSYS_SW_PORT_MODE(CPU_PORT)); 777*2ea1cbacSHoratiu Vultur 778*2ea1cbacSHoratiu Vultur return err; 779*2ea1cbacSHoratiu Vultur } 780*2ea1cbacSHoratiu Vultur 781c8349639SHoratiu Vultur void lan966x_fdma_netdev_init(struct lan966x *lan966x, struct net_device *dev) 782c8349639SHoratiu Vultur { 783c8349639SHoratiu Vultur if (lan966x->fdma_ndev) 784c8349639SHoratiu Vultur return; 785c8349639SHoratiu Vultur 786c8349639SHoratiu Vultur lan966x->fdma_ndev = dev; 787c8349639SHoratiu Vultur netif_napi_add(dev, &lan966x->napi, lan966x_fdma_napi_poll, 788c8349639SHoratiu Vultur NAPI_POLL_WEIGHT); 789c8349639SHoratiu Vultur napi_enable(&lan966x->napi); 790c8349639SHoratiu Vultur } 791c8349639SHoratiu Vultur 792c8349639SHoratiu Vultur void lan966x_fdma_netdev_deinit(struct lan966x *lan966x, struct net_device *dev) 793c8349639SHoratiu Vultur { 794c8349639SHoratiu Vultur if (lan966x->fdma_ndev == dev) { 795c8349639SHoratiu Vultur netif_napi_del(&lan966x->napi); 796c8349639SHoratiu Vultur lan966x->fdma_ndev = NULL; 797c8349639SHoratiu Vultur } 798c8349639SHoratiu Vultur } 799c8349639SHoratiu Vultur 800c8349639SHoratiu Vultur int lan966x_fdma_init(struct lan966x *lan966x) 801c8349639SHoratiu Vultur { 802c8349639SHoratiu Vultur int err; 803c8349639SHoratiu Vultur 804c8349639SHoratiu Vultur if (!lan966x->fdma) 805c8349639SHoratiu Vultur return 0; 806c8349639SHoratiu Vultur 807c8349639SHoratiu Vultur lan966x->rx.lan966x = lan966x; 808c8349639SHoratiu Vultur lan966x->rx.channel_id = FDMA_XTR_CHANNEL; 809c8349639SHoratiu Vultur lan966x->tx.lan966x = lan966x; 810c8349639SHoratiu Vultur lan966x->tx.channel_id = FDMA_INJ_CHANNEL; 811c8349639SHoratiu Vultur lan966x->tx.last_in_use = -1; 812c8349639SHoratiu Vultur 813c8349639SHoratiu Vultur err = lan966x_fdma_rx_alloc(&lan966x->rx); 814c8349639SHoratiu Vultur if (err) 815c8349639SHoratiu Vultur return err; 816c8349639SHoratiu Vultur 817c8349639SHoratiu Vultur err = lan966x_fdma_tx_alloc(&lan966x->tx); 818c8349639SHoratiu Vultur if (err) { 819c8349639SHoratiu Vultur lan966x_fdma_rx_free(&lan966x->rx); 820c8349639SHoratiu Vultur return err; 821c8349639SHoratiu Vultur } 822c8349639SHoratiu Vultur 823c8349639SHoratiu Vultur lan966x_fdma_rx_start(&lan966x->rx); 824c8349639SHoratiu Vultur 825c8349639SHoratiu Vultur return 0; 826c8349639SHoratiu Vultur } 827c8349639SHoratiu Vultur 828c8349639SHoratiu Vultur void lan966x_fdma_deinit(struct lan966x *lan966x) 829c8349639SHoratiu Vultur { 830c8349639SHoratiu Vultur if (!lan966x->fdma) 831c8349639SHoratiu Vultur return; 832c8349639SHoratiu Vultur 833c8349639SHoratiu Vultur lan966x_fdma_rx_disable(&lan966x->rx); 834c8349639SHoratiu Vultur lan966x_fdma_tx_disable(&lan966x->tx); 835c8349639SHoratiu Vultur 836c8349639SHoratiu Vultur napi_synchronize(&lan966x->napi); 837c8349639SHoratiu Vultur napi_disable(&lan966x->napi); 838c8349639SHoratiu Vultur 839c8349639SHoratiu Vultur lan966x_fdma_rx_free_pages(&lan966x->rx); 840c8349639SHoratiu Vultur lan966x_fdma_rx_free(&lan966x->rx); 841c8349639SHoratiu Vultur lan966x_fdma_tx_free(&lan966x->tx); 842c8349639SHoratiu Vultur } 843