Commit a5144237ac6dce3a38a73a51c217636a37d1e0b6
Committed by
Joe Hershberger
1 parent
f27f3b5266
Exists in
master
and in
50 other branches
net: zynq_gem: Add d-cache support
Added d-cache support for zynq_gem.c, Observed a difference of +0.8 MiB/s when downloading a file of size of 3007944Bytes. With d-cache OFF: ---------------- Filename 'uImage'. Load address: 0x800 Loading: ################################################################# ################################################################# ################################################################# ########## 1.3 MiB/s done Bytes transferred = 3007944 (2de5c8 hex) With d-cache ON: --------------- Filename 'uImage'. Load address: 0x800 Loading: ################################################################# ################################################################# ################################################################# ########## 2.1 MiB/s done Bytes transferred = 3007944 (2de5c8 hex) Changes on zynq_gem for d-cache support: - Tx and Rx buffers are cache-aligned - Updated logic for invalidating Rx buffers and flushing Tx buffers. - Tx and Rx BD's are allocated from non-cacheable region. (When BDs are cached, we don't see a consistent link) - Use TX BD status intead of txsr status checks. Signed-off-by: Srikanth Thokala <sthokal@xilinx.com> Signed-off-by: Jagannadha Sutradharudu Teki <jaganna@xilinx.com> Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Showing 1 changed file with 53 additions and 29 deletions Side-by-side Diff
drivers/net/zynq_gem.c
... | ... | @@ -43,11 +43,6 @@ |
43 | 43 | #define ZYNQ_GEM_TXBUF_WRAP_MASK 0x40000000 |
44 | 44 | #define ZYNQ_GEM_TXBUF_LAST_MASK 0x00008000 /* Last buffer */ |
45 | 45 | |
46 | -#define ZYNQ_GEM_TXSR_HRESPNOK_MASK 0x00000100 /* Transmit hresp not OK */ | |
47 | -#define ZYNQ_GEM_TXSR_URUN_MASK 0x00000040 /* Transmit underrun */ | |
48 | -/* Transmit buffs exhausted mid frame */ | |
49 | -#define ZYNQ_GEM_TXSR_BUFEXH_MASK 0x00000010 | |
50 | - | |
51 | 46 | #define ZYNQ_GEM_NWCTRL_TXEN_MASK 0x00000008 /* Enable transmit */ |
52 | 47 | #define ZYNQ_GEM_NWCTRL_RXEN_MASK 0x00000004 /* Enable receive */ |
53 | 48 | #define ZYNQ_GEM_NWCTRL_MDEN_MASK 0x00000010 /* Enable MDIO port */ |
... | ... | @@ -90,6 +85,11 @@ |
90 | 85 | */ |
91 | 86 | #define PHY_DETECT_MASK 0x1808 |
92 | 87 | |
88 | +/* TX BD status masks */ | |
89 | +#define ZYNQ_GEM_TXBUF_FRMLEN_MASK 0x000007ff | |
90 | +#define ZYNQ_GEM_TXBUF_EXHAUSTED 0x08000000 | |
91 | +#define ZYNQ_GEM_TXBUF_UNDERRUN 0x10000000 | |
92 | + | |
93 | 93 | /* Device registers */ |
94 | 94 | struct zynq_gem_regs { |
95 | 95 | u32 nwctrl; /* Network Control reg */ |
96 | 96 | |
... | ... | @@ -123,12 +123,18 @@ |
123 | 123 | }; |
124 | 124 | |
125 | 125 | #define RX_BUF 3 |
126 | +/* Page table entries are set to 1MB, or multiples of 1MB | |
127 | + * (not < 1MB). driver uses less bd's so use 1MB bdspace. | |
128 | + */ | |
129 | +#define BD_SPACE 0x100000 | |
130 | +/* BD separation space */ | |
131 | +#define BD_SEPRN_SPACE 64 | |
126 | 132 | |
127 | 133 | /* Initialized, rxbd_current, rx_first_buf must be 0 after init */ |
128 | 134 | struct zynq_gem_priv { |
129 | - struct emac_bd tx_bd; | |
130 | - struct emac_bd rx_bd[RX_BUF]; | |
131 | - char rxbuffers[RX_BUF * PKTSIZE_ALIGN]; | |
135 | + struct emac_bd *tx_bd; | |
136 | + struct emac_bd *rx_bd; | |
137 | + char *rxbuffers; | |
132 | 138 | u32 rxbd_current; |
133 | 139 | u32 rx_first_buf; |
134 | 140 | int phyaddr; |
135 | 141 | |
136 | 142 | |
... | ... | @@ -299,20 +305,18 @@ |
299 | 305 | readl(®s->stat[i]); |
300 | 306 | |
301 | 307 | /* Setup RxBD space */ |
302 | - memset(&(priv->rx_bd), 0, sizeof(priv->rx_bd)); | |
303 | - /* Create the RxBD ring */ | |
304 | - memset(&(priv->rxbuffers), 0, sizeof(priv->rxbuffers)); | |
308 | + memset(priv->rx_bd, 0, RX_BUF * sizeof(struct emac_bd)); | |
305 | 309 | |
306 | 310 | for (i = 0; i < RX_BUF; i++) { |
307 | 311 | priv->rx_bd[i].status = 0xF0000000; |
308 | 312 | priv->rx_bd[i].addr = |
309 | - (u32)((char *)&(priv->rxbuffers) + | |
313 | + ((u32)(priv->rxbuffers) + | |
310 | 314 | (i * PKTSIZE_ALIGN)); |
311 | 315 | } |
312 | 316 | /* WRAP bit to last BD */ |
313 | 317 | priv->rx_bd[--i].addr |= ZYNQ_GEM_RXBUF_WRAP_MASK; |
314 | 318 | /* Write RxBDs to IP */ |
315 | - writel((u32)&(priv->rx_bd), ®s->rxqbase); | |
319 | + writel((u32)priv->rx_bd, ®s->rxqbase); | |
316 | 320 | |
317 | 321 | /* Setup for DMA Configuration register */ |
318 | 322 | writel(ZYNQ_GEM_DMACR_INIT, ®s->dmacr); |
319 | 323 | |
320 | 324 | |
321 | 325 | |
322 | 326 | |
323 | 327 | |
324 | 328 | |
325 | 329 | |
... | ... | @@ -368,32 +372,35 @@ |
368 | 372 | |
369 | 373 | static int zynq_gem_send(struct eth_device *dev, void *ptr, int len) |
370 | 374 | { |
371 | - u32 status; | |
375 | + u32 addr, size; | |
372 | 376 | struct zynq_gem_priv *priv = dev->priv; |
373 | 377 | struct zynq_gem_regs *regs = (struct zynq_gem_regs *)dev->iobase; |
374 | - const u32 mask = ZYNQ_GEM_TXSR_HRESPNOK_MASK | \ | |
375 | - ZYNQ_GEM_TXSR_URUN_MASK | ZYNQ_GEM_TXSR_BUFEXH_MASK; | |
376 | 378 | |
377 | 379 | /* setup BD */ |
378 | - writel((u32)&(priv->tx_bd), ®s->txqbase); | |
380 | + writel((u32)priv->tx_bd, ®s->txqbase); | |
379 | 381 | |
380 | 382 | /* Setup Tx BD */ |
381 | - memset((void *)&(priv->tx_bd), 0, sizeof(struct emac_bd)); | |
383 | + memset(priv->tx_bd, 0, sizeof(struct emac_bd)); | |
382 | 384 | |
383 | - priv->tx_bd.addr = (u32)ptr; | |
384 | - priv->tx_bd.status = len | ZYNQ_GEM_TXBUF_LAST_MASK; | |
385 | + priv->tx_bd->addr = (u32)ptr; | |
386 | + priv->tx_bd->status = (len & ZYNQ_GEM_TXBUF_FRMLEN_MASK) | | |
387 | + ZYNQ_GEM_TXBUF_LAST_MASK; | |
385 | 388 | |
389 | + addr = (u32) ptr; | |
390 | + addr &= ~(ARCH_DMA_MINALIGN - 1); | |
391 | + size = roundup(len, ARCH_DMA_MINALIGN); | |
392 | + flush_dcache_range(addr, addr + size); | |
393 | + barrier(); | |
394 | + | |
386 | 395 | /* Start transmit */ |
387 | 396 | setbits_le32(®s->nwctrl, ZYNQ_GEM_NWCTRL_STARTTX_MASK); |
388 | 397 | |
389 | - /* Read the stat register to know if the packet has been transmitted */ | |
390 | - status = readl(®s->txsr); | |
391 | - if (status & mask) | |
392 | - printf("Something has gone wrong here!? Status is 0x%x.\n", | |
393 | - status); | |
398 | + /* Read TX BD status */ | |
399 | + if (priv->tx_bd->status & ZYNQ_GEM_TXBUF_UNDERRUN) | |
400 | + printf("TX underrun\n"); | |
401 | + if (priv->tx_bd->status & ZYNQ_GEM_TXBUF_EXHAUSTED) | |
402 | + printf("TX buffers exhausted in mid frame\n"); | |
394 | 403 | |
395 | - /* Clear Tx status register before leaving . */ | |
396 | - writel(status, ®s->txsr); | |
397 | 404 | return 0; |
398 | 405 | } |
399 | 406 | |
400 | 407 | |
... | ... | @@ -416,9 +423,13 @@ |
416 | 423 | |
417 | 424 | frame_len = current_bd->status & ZYNQ_GEM_RXBUF_LEN_MASK; |
418 | 425 | if (frame_len) { |
419 | - NetReceive((u8 *) (current_bd->addr & | |
420 | - ZYNQ_GEM_RXBUF_ADD_MASK), frame_len); | |
426 | + u32 addr = current_bd->addr & ZYNQ_GEM_RXBUF_ADD_MASK; | |
427 | + addr &= ~(ARCH_DMA_MINALIGN - 1); | |
428 | + u32 size = roundup(frame_len, ARCH_DMA_MINALIGN); | |
429 | + invalidate_dcache_range(addr, addr + size); | |
421 | 430 | |
431 | + NetReceive((u8 *)addr, frame_len); | |
432 | + | |
422 | 433 | if (current_bd->status & ZYNQ_GEM_RXBUF_SOF_MASK) |
423 | 434 | priv->rx_first_buf = priv->rxbd_current; |
424 | 435 | else { |
... | ... | @@ -471,6 +482,7 @@ |
471 | 482 | { |
472 | 483 | struct eth_device *dev; |
473 | 484 | struct zynq_gem_priv *priv; |
485 | + void *bd_space; | |
474 | 486 | |
475 | 487 | dev = calloc(1, sizeof(*dev)); |
476 | 488 | if (dev == NULL) |
... | ... | @@ -482,6 +494,18 @@ |
482 | 494 | return -1; |
483 | 495 | } |
484 | 496 | priv = dev->priv; |
497 | + | |
498 | + /* Align rxbuffers to ARCH_DMA_MINALIGN */ | |
499 | + priv->rxbuffers = memalign(ARCH_DMA_MINALIGN, RX_BUF * PKTSIZE_ALIGN); | |
500 | + memset(priv->rxbuffers, 0, RX_BUF * PKTSIZE_ALIGN); | |
501 | + | |
502 | + /* Align bd_space to 1MB */ | |
503 | + bd_space = memalign(1 << MMU_SECTION_SHIFT, BD_SPACE); | |
504 | + mmu_set_region_dcache_behaviour((u32)bd_space, BD_SPACE, DCACHE_OFF); | |
505 | + | |
506 | + /* Initialize the bd spaces for tx and rx bd's */ | |
507 | + priv->tx_bd = (struct emac_bd *)bd_space; | |
508 | + priv->rx_bd = (struct emac_bd *)((u32)bd_space + BD_SEPRN_SPACE); | |
485 | 509 | |
486 | 510 | priv->phyaddr = phy_addr; |
487 | 511 | priv->emio = emio; |