Commit a5144237ac6dce3a38a73a51c217636a37d1e0b6

Authored by Srikanth Thokala
Committed by Joe Hershberger
1 parent f27f3b5266

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(&regs->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), &regs->rxqbase);
  319 + writel((u32)priv->rx_bd, &regs->rxqbase);
316 320  
317 321 /* Setup for DMA Configuration register */
318 322 writel(ZYNQ_GEM_DMACR_INIT, &regs->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), &regs->txqbase);
  380 + writel((u32)priv->tx_bd, &regs->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(&regs->nwctrl, ZYNQ_GEM_NWCTRL_STARTTX_MASK);
388 397  
389   - /* Read the stat register to know if the packet has been transmitted */
390   - status = readl(&regs->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, &regs->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;