xref: /openbmc/qemu/hw/net/allwinner-sun8i-emac.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
1  /*
2   * Allwinner Sun8i Ethernet MAC emulation
3   *
4   * Copyright (C) 2019 Niek Linnenbank <nieklinnenbank@gmail.com>
5   *
6   * This program is free software: you can redistribute it and/or modify
7   * it under the terms of the GNU General Public License as published by
8   * the Free Software Foundation, either version 2 of the License, or
9   * (at your option) any later version.
10   *
11   * This program is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   * GNU General Public License for more details.
15   *
16   * You should have received a copy of the GNU General Public License
17   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18   */
19  
20  #include "qemu/osdep.h"
21  #include "qemu/units.h"
22  #include "qapi/error.h"
23  #include "hw/sysbus.h"
24  #include "migration/vmstate.h"
25  #include "net/net.h"
26  #include "hw/irq.h"
27  #include "hw/qdev-properties.h"
28  #include "qemu/log.h"
29  #include "trace.h"
30  #include "net/checksum.h"
31  #include "qemu/module.h"
32  #include "exec/cpu-common.h"
33  #include "sysemu/dma.h"
34  #include "hw/net/allwinner-sun8i-emac.h"
35  
36  /* EMAC register offsets */
37  enum {
38      REG_BASIC_CTL_0        = 0x0000, /* Basic Control 0 */
39      REG_BASIC_CTL_1        = 0x0004, /* Basic Control 1 */
40      REG_INT_STA            = 0x0008, /* Interrupt Status */
41      REG_INT_EN             = 0x000C, /* Interrupt Enable */
42      REG_TX_CTL_0           = 0x0010, /* Transmit Control 0 */
43      REG_TX_CTL_1           = 0x0014, /* Transmit Control 1 */
44      REG_TX_FLOW_CTL        = 0x001C, /* Transmit Flow Control */
45      REG_TX_DMA_DESC_LIST   = 0x0020, /* Transmit Descriptor List Address */
46      REG_RX_CTL_0           = 0x0024, /* Receive Control 0 */
47      REG_RX_CTL_1           = 0x0028, /* Receive Control 1 */
48      REG_RX_DMA_DESC_LIST   = 0x0034, /* Receive Descriptor List Address */
49      REG_FRM_FLT            = 0x0038, /* Receive Frame Filter */
50      REG_RX_HASH_0          = 0x0040, /* Receive Hash Table 0 */
51      REG_RX_HASH_1          = 0x0044, /* Receive Hash Table 1 */
52      REG_MII_CMD            = 0x0048, /* Management Interface Command */
53      REG_MII_DATA           = 0x004C, /* Management Interface Data */
54      REG_ADDR_HIGH          = 0x0050, /* MAC Address High */
55      REG_ADDR_LOW           = 0x0054, /* MAC Address Low */
56      REG_TX_DMA_STA         = 0x00B0, /* Transmit DMA Status */
57      REG_TX_CUR_DESC        = 0x00B4, /* Transmit Current Descriptor */
58      REG_TX_CUR_BUF         = 0x00B8, /* Transmit Current Buffer */
59      REG_RX_DMA_STA         = 0x00C0, /* Receive DMA Status */
60      REG_RX_CUR_DESC        = 0x00C4, /* Receive Current Descriptor */
61      REG_RX_CUR_BUF         = 0x00C8, /* Receive Current Buffer */
62      REG_RGMII_STA          = 0x00D0, /* RGMII Status */
63  };
64  
65  /* EMAC register flags */
66  enum {
67      BASIC_CTL0_100Mbps     = (0b11 << 2),
68      BASIC_CTL0_FD          = (1 << 0),
69      BASIC_CTL1_SOFTRST     = (1 << 0),
70  };
71  
72  enum {
73      INT_STA_RGMII_LINK     = (1 << 16),
74      INT_STA_RX_EARLY       = (1 << 13),
75      INT_STA_RX_OVERFLOW    = (1 << 12),
76      INT_STA_RX_TIMEOUT     = (1 << 11),
77      INT_STA_RX_DMA_STOP    = (1 << 10),
78      INT_STA_RX_BUF_UA      = (1 << 9),
79      INT_STA_RX             = (1 << 8),
80      INT_STA_TX_EARLY       = (1 << 5),
81      INT_STA_TX_UNDERFLOW   = (1 << 4),
82      INT_STA_TX_TIMEOUT     = (1 << 3),
83      INT_STA_TX_BUF_UA      = (1 << 2),
84      INT_STA_TX_DMA_STOP    = (1 << 1),
85      INT_STA_TX             = (1 << 0),
86  };
87  
88  enum {
89      INT_EN_RX_EARLY        = (1 << 13),
90      INT_EN_RX_OVERFLOW     = (1 << 12),
91      INT_EN_RX_TIMEOUT      = (1 << 11),
92      INT_EN_RX_DMA_STOP     = (1 << 10),
93      INT_EN_RX_BUF_UA       = (1 << 9),
94      INT_EN_RX              = (1 << 8),
95      INT_EN_TX_EARLY        = (1 << 5),
96      INT_EN_TX_UNDERFLOW    = (1 << 4),
97      INT_EN_TX_TIMEOUT      = (1 << 3),
98      INT_EN_TX_BUF_UA       = (1 << 2),
99      INT_EN_TX_DMA_STOP     = (1 << 1),
100      INT_EN_TX              = (1 << 0),
101  };
102  
103  enum {
104      TX_CTL0_TX_EN          = (1 << 31),
105      TX_CTL1_TX_DMA_START   = (1 << 31),
106      TX_CTL1_TX_DMA_EN      = (1 << 30),
107      TX_CTL1_TX_FLUSH       = (1 << 0),
108  };
109  
110  enum {
111      RX_CTL0_RX_EN          = (1 << 31),
112      RX_CTL0_STRIP_FCS      = (1 << 28),
113      RX_CTL0_CRC_IPV4       = (1 << 27),
114  };
115  
116  enum {
117      RX_CTL1_RX_DMA_START   = (1 << 31),
118      RX_CTL1_RX_DMA_EN      = (1 << 30),
119      RX_CTL1_RX_MD          = (1 << 1),
120  };
121  
122  enum {
123      RX_FRM_FLT_DIS_ADDR    = (1 << 31),
124  };
125  
126  enum {
127      MII_CMD_PHY_ADDR_SHIFT = (12),
128      MII_CMD_PHY_ADDR_MASK  = (0xf000),
129      MII_CMD_PHY_REG_SHIFT  = (4),
130      MII_CMD_PHY_REG_MASK   = (0xf0),
131      MII_CMD_PHY_RW         = (1 << 1),
132      MII_CMD_PHY_BUSY       = (1 << 0),
133  };
134  
135  enum {
136      TX_DMA_STA_STOP        = (0b000),
137      TX_DMA_STA_RUN_FETCH   = (0b001),
138      TX_DMA_STA_WAIT_STA    = (0b010),
139  };
140  
141  enum {
142      RX_DMA_STA_STOP        = (0b000),
143      RX_DMA_STA_RUN_FETCH   = (0b001),
144      RX_DMA_STA_WAIT_FRM    = (0b011),
145  };
146  
147  /* EMAC register reset values */
148  enum {
149      REG_BASIC_CTL_1_RST    = 0x08000000,
150  };
151  
152  /* EMAC constants */
153  enum {
154      AW_SUN8I_EMAC_MIN_PKT_SZ  = 64
155  };
156  
157  /* Transmit/receive frame descriptor */
158  typedef struct FrameDescriptor {
159      uint32_t status;
160      uint32_t status2;
161      uint32_t addr;
162      uint32_t next;
163  } FrameDescriptor;
164  
165  /* Frame descriptor flags */
166  enum {
167      DESC_STATUS_CTL                 = (1 << 31),
168      DESC_STATUS2_BUF_SIZE_MASK      = (0x7ff),
169  };
170  
171  /* Transmit frame descriptor flags */
172  enum {
173      TX_DESC_STATUS_LENGTH_ERR       = (1 << 14),
174      TX_DESC_STATUS2_FIRST_DESC      = (1 << 29),
175      TX_DESC_STATUS2_LAST_DESC       = (1 << 30),
176      TX_DESC_STATUS2_CHECKSUM_MASK   = (0x3 << 27),
177  };
178  
179  /* Receive frame descriptor flags */
180  enum {
181      RX_DESC_STATUS_FIRST_DESC       = (1 << 9),
182      RX_DESC_STATUS_LAST_DESC        = (1 << 8),
183      RX_DESC_STATUS_FRM_LEN_MASK     = (0x3fff0000),
184      RX_DESC_STATUS_FRM_LEN_SHIFT    = (16),
185      RX_DESC_STATUS_NO_BUF           = (1 << 14),
186      RX_DESC_STATUS_HEADER_ERR       = (1 << 7),
187      RX_DESC_STATUS_LENGTH_ERR       = (1 << 4),
188      RX_DESC_STATUS_CRC_ERR          = (1 << 1),
189      RX_DESC_STATUS_PAYLOAD_ERR      = (1 << 0),
190      RX_DESC_STATUS2_RX_INT_CTL      = (1 << 31),
191  };
192  
193  /* MII register offsets */
194  enum {
195      MII_REG_CR                      = (0x0), /* Control */
196      MII_REG_ST                      = (0x1), /* Status */
197      MII_REG_ID_HIGH                 = (0x2), /* Identifier High */
198      MII_REG_ID_LOW                  = (0x3), /* Identifier Low */
199      MII_REG_ADV                     = (0x4), /* Advertised abilities */
200      MII_REG_LPA                     = (0x5), /* Link partner abilities */
201  };
202  
203  /* MII register flags */
204  enum {
205      MII_REG_CR_RESET                = (1 << 15),
206      MII_REG_CR_POWERDOWN            = (1 << 11),
207      MII_REG_CR_10Mbit               = (0),
208      MII_REG_CR_100Mbit              = (1 << 13),
209      MII_REG_CR_1000Mbit             = (1 << 6),
210      MII_REG_CR_AUTO_NEG             = (1 << 12),
211      MII_REG_CR_AUTO_NEG_RESTART     = (1 << 9),
212      MII_REG_CR_FULLDUPLEX           = (1 << 8),
213  };
214  
215  enum {
216      MII_REG_ST_100BASE_T4           = (1 << 15),
217      MII_REG_ST_100BASE_X_FD         = (1 << 14),
218      MII_REG_ST_100BASE_X_HD         = (1 << 13),
219      MII_REG_ST_10_FD                = (1 << 12),
220      MII_REG_ST_10_HD                = (1 << 11),
221      MII_REG_ST_100BASE_T2_FD        = (1 << 10),
222      MII_REG_ST_100BASE_T2_HD        = (1 << 9),
223      MII_REG_ST_AUTONEG_COMPLETE     = (1 << 5),
224      MII_REG_ST_AUTONEG_AVAIL        = (1 << 3),
225      MII_REG_ST_LINK_UP              = (1 << 2),
226  };
227  
228  enum {
229      MII_REG_LPA_10_HD               = (1 << 5),
230      MII_REG_LPA_10_FD               = (1 << 6),
231      MII_REG_LPA_100_HD              = (1 << 7),
232      MII_REG_LPA_100_FD              = (1 << 8),
233      MII_REG_LPA_PAUSE               = (1 << 10),
234      MII_REG_LPA_ASYMPAUSE           = (1 << 11),
235  };
236  
237  /* MII constants */
238  enum {
239      MII_PHY_ID_HIGH                 = 0x0044,
240      MII_PHY_ID_LOW                  = 0x1400,
241  };
242  
allwinner_sun8i_emac_mii_set_link(AwSun8iEmacState * s,bool link_active)243  static void allwinner_sun8i_emac_mii_set_link(AwSun8iEmacState *s,
244                                                bool link_active)
245  {
246      if (link_active) {
247          s->mii_st |= MII_REG_ST_LINK_UP;
248      } else {
249          s->mii_st &= ~MII_REG_ST_LINK_UP;
250      }
251  }
252  
allwinner_sun8i_emac_mii_reset(AwSun8iEmacState * s,bool link_active)253  static void allwinner_sun8i_emac_mii_reset(AwSun8iEmacState *s,
254                                             bool link_active)
255  {
256      s->mii_cr = MII_REG_CR_100Mbit | MII_REG_CR_AUTO_NEG |
257                  MII_REG_CR_FULLDUPLEX;
258      s->mii_st = MII_REG_ST_100BASE_T4 | MII_REG_ST_100BASE_X_FD |
259                  MII_REG_ST_100BASE_X_HD | MII_REG_ST_10_FD | MII_REG_ST_10_HD |
260                  MII_REG_ST_100BASE_T2_FD | MII_REG_ST_100BASE_T2_HD |
261                  MII_REG_ST_AUTONEG_COMPLETE | MII_REG_ST_AUTONEG_AVAIL;
262      s->mii_adv = 0;
263  
264      allwinner_sun8i_emac_mii_set_link(s, link_active);
265  }
266  
allwinner_sun8i_emac_mii_cmd(AwSun8iEmacState * s)267  static void allwinner_sun8i_emac_mii_cmd(AwSun8iEmacState *s)
268  {
269      uint8_t addr, reg;
270  
271      addr = (s->mii_cmd & MII_CMD_PHY_ADDR_MASK) >> MII_CMD_PHY_ADDR_SHIFT;
272      reg = (s->mii_cmd & MII_CMD_PHY_REG_MASK) >> MII_CMD_PHY_REG_SHIFT;
273  
274      if (addr != s->mii_phy_addr) {
275          return;
276      }
277  
278      /* Read or write a PHY register? */
279      if (s->mii_cmd & MII_CMD_PHY_RW) {
280          trace_allwinner_sun8i_emac_mii_write_reg(reg, s->mii_data);
281  
282          switch (reg) {
283          case MII_REG_CR:
284              if (s->mii_data & MII_REG_CR_RESET) {
285                  allwinner_sun8i_emac_mii_reset(s, s->mii_st &
286                                                    MII_REG_ST_LINK_UP);
287              } else {
288                  s->mii_cr = s->mii_data & ~(MII_REG_CR_RESET |
289                                              MII_REG_CR_AUTO_NEG_RESTART);
290              }
291              break;
292          case MII_REG_ADV:
293              s->mii_adv = s->mii_data;
294              break;
295          case MII_REG_ID_HIGH:
296          case MII_REG_ID_LOW:
297          case MII_REG_LPA:
298              break;
299          default:
300              qemu_log_mask(LOG_UNIMP, "allwinner-h3-emac: write access to "
301                                       "unknown MII register 0x%x\n", reg);
302              break;
303          }
304      } else {
305          switch (reg) {
306          case MII_REG_CR:
307              s->mii_data = s->mii_cr;
308              break;
309          case MII_REG_ST:
310              s->mii_data = s->mii_st;
311              break;
312          case MII_REG_ID_HIGH:
313              s->mii_data = MII_PHY_ID_HIGH;
314              break;
315          case MII_REG_ID_LOW:
316              s->mii_data = MII_PHY_ID_LOW;
317              break;
318          case MII_REG_ADV:
319              s->mii_data = s->mii_adv;
320              break;
321          case MII_REG_LPA:
322              s->mii_data = MII_REG_LPA_10_HD | MII_REG_LPA_10_FD |
323                            MII_REG_LPA_100_HD | MII_REG_LPA_100_FD |
324                            MII_REG_LPA_PAUSE | MII_REG_LPA_ASYMPAUSE;
325              break;
326          default:
327              qemu_log_mask(LOG_UNIMP, "allwinner-h3-emac: read access to "
328                                       "unknown MII register 0x%x\n", reg);
329              s->mii_data = 0;
330              break;
331          }
332  
333          trace_allwinner_sun8i_emac_mii_read_reg(reg, s->mii_data);
334      }
335  }
336  
allwinner_sun8i_emac_update_irq(AwSun8iEmacState * s)337  static void allwinner_sun8i_emac_update_irq(AwSun8iEmacState *s)
338  {
339      qemu_set_irq(s->irq, (s->int_sta & s->int_en) != 0);
340  }
341  
allwinner_sun8i_emac_desc_owned(FrameDescriptor * desc,size_t min_buf_size)342  static bool allwinner_sun8i_emac_desc_owned(FrameDescriptor *desc,
343                                              size_t min_buf_size)
344  {
345      return (desc->status & DESC_STATUS_CTL) && (min_buf_size == 0 ||
346             (desc->status2 & DESC_STATUS2_BUF_SIZE_MASK) >= min_buf_size);
347  }
348  
allwinner_sun8i_emac_get_desc(AwSun8iEmacState * s,FrameDescriptor * desc,uint32_t phys_addr)349  static void allwinner_sun8i_emac_get_desc(AwSun8iEmacState *s,
350                                            FrameDescriptor *desc,
351                                            uint32_t phys_addr)
352  {
353      uint32_t desc_words[4];
354      dma_memory_read(&s->dma_as, phys_addr, &desc_words, sizeof(desc_words),
355                      MEMTXATTRS_UNSPECIFIED);
356      desc->status = le32_to_cpu(desc_words[0]);
357      desc->status2 = le32_to_cpu(desc_words[1]);
358      desc->addr = le32_to_cpu(desc_words[2]);
359      desc->next = le32_to_cpu(desc_words[3]);
360  }
361  
allwinner_sun8i_emac_next_desc(AwSun8iEmacState * s,FrameDescriptor * desc)362  static uint32_t allwinner_sun8i_emac_next_desc(AwSun8iEmacState *s,
363                                                 FrameDescriptor *desc)
364  {
365      const uint32_t nxt = desc->next;
366      allwinner_sun8i_emac_get_desc(s, desc, nxt);
367      return nxt;
368  }
369  
allwinner_sun8i_emac_find_desc(AwSun8iEmacState * s,FrameDescriptor * desc,uint32_t start_addr,size_t min_size)370  static uint32_t allwinner_sun8i_emac_find_desc(AwSun8iEmacState *s,
371                                                 FrameDescriptor *desc,
372                                                 uint32_t start_addr,
373                                                 size_t min_size)
374  {
375      uint32_t desc_addr = start_addr;
376  
377      /* Note that the list is a cycle. Last entry points back to the head. */
378      while (desc_addr != 0) {
379          allwinner_sun8i_emac_get_desc(s, desc, desc_addr);
380  
381          if (allwinner_sun8i_emac_desc_owned(desc, min_size)) {
382              return desc_addr;
383          } else if (desc->next == start_addr) {
384              break;
385          } else {
386              desc_addr = desc->next;
387          }
388      }
389  
390      return 0;
391  }
392  
allwinner_sun8i_emac_rx_desc(AwSun8iEmacState * s,FrameDescriptor * desc,size_t min_size)393  static uint32_t allwinner_sun8i_emac_rx_desc(AwSun8iEmacState *s,
394                                               FrameDescriptor *desc,
395                                               size_t min_size)
396  {
397      return allwinner_sun8i_emac_find_desc(s, desc, s->rx_desc_curr, min_size);
398  }
399  
allwinner_sun8i_emac_tx_desc(AwSun8iEmacState * s,FrameDescriptor * desc)400  static uint32_t allwinner_sun8i_emac_tx_desc(AwSun8iEmacState *s,
401                                               FrameDescriptor *desc)
402  {
403      allwinner_sun8i_emac_get_desc(s, desc, s->tx_desc_curr);
404      return s->tx_desc_curr;
405  }
406  
allwinner_sun8i_emac_flush_desc(AwSun8iEmacState * s,const FrameDescriptor * desc,uint32_t phys_addr)407  static void allwinner_sun8i_emac_flush_desc(AwSun8iEmacState *s,
408                                              const FrameDescriptor *desc,
409                                              uint32_t phys_addr)
410  {
411      uint32_t desc_words[4];
412      desc_words[0] = cpu_to_le32(desc->status);
413      desc_words[1] = cpu_to_le32(desc->status2);
414      desc_words[2] = cpu_to_le32(desc->addr);
415      desc_words[3] = cpu_to_le32(desc->next);
416      dma_memory_write(&s->dma_as, phys_addr, &desc_words, sizeof(desc_words),
417                       MEMTXATTRS_UNSPECIFIED);
418  }
419  
allwinner_sun8i_emac_can_receive(NetClientState * nc)420  static bool allwinner_sun8i_emac_can_receive(NetClientState *nc)
421  {
422      AwSun8iEmacState *s = qemu_get_nic_opaque(nc);
423      FrameDescriptor desc;
424  
425      return (s->rx_ctl0 & RX_CTL0_RX_EN) &&
426             (allwinner_sun8i_emac_rx_desc(s, &desc, 0) != 0);
427  }
428  
allwinner_sun8i_emac_receive(NetClientState * nc,const uint8_t * buf,size_t size)429  static ssize_t allwinner_sun8i_emac_receive(NetClientState *nc,
430                                              const uint8_t *buf,
431                                              size_t size)
432  {
433      AwSun8iEmacState *s = qemu_get_nic_opaque(nc);
434      FrameDescriptor desc;
435      size_t bytes_left = size;
436      size_t desc_bytes = 0;
437      size_t pad_fcs_size = 4;
438      size_t padding = 0;
439  
440      if (!(s->rx_ctl0 & RX_CTL0_RX_EN)) {
441          return -1;
442      }
443  
444      s->rx_desc_curr = allwinner_sun8i_emac_rx_desc(s, &desc,
445                                                     AW_SUN8I_EMAC_MIN_PKT_SZ);
446      if (!s->rx_desc_curr) {
447          s->int_sta |= INT_STA_RX_BUF_UA;
448      }
449  
450      /* Keep filling RX descriptors until the whole frame is written */
451      while (s->rx_desc_curr && bytes_left > 0) {
452          desc.status &= ~DESC_STATUS_CTL;
453          desc.status &= ~RX_DESC_STATUS_FRM_LEN_MASK;
454  
455          if (bytes_left == size) {
456              desc.status |= RX_DESC_STATUS_FIRST_DESC;
457          }
458  
459          if ((desc.status2 & DESC_STATUS2_BUF_SIZE_MASK) <
460              (bytes_left + pad_fcs_size)) {
461              desc_bytes = desc.status2 & DESC_STATUS2_BUF_SIZE_MASK;
462              desc.status |= desc_bytes << RX_DESC_STATUS_FRM_LEN_SHIFT;
463          } else {
464              padding = pad_fcs_size;
465              if (bytes_left < AW_SUN8I_EMAC_MIN_PKT_SZ) {
466                  padding += (AW_SUN8I_EMAC_MIN_PKT_SZ - bytes_left);
467              }
468  
469              desc_bytes = (bytes_left);
470              desc.status |= RX_DESC_STATUS_LAST_DESC;
471              desc.status |= (bytes_left + padding)
472                              << RX_DESC_STATUS_FRM_LEN_SHIFT;
473          }
474  
475          dma_memory_write(&s->dma_as, desc.addr, buf, desc_bytes,
476                           MEMTXATTRS_UNSPECIFIED);
477          allwinner_sun8i_emac_flush_desc(s, &desc, s->rx_desc_curr);
478          trace_allwinner_sun8i_emac_receive(s->rx_desc_curr, desc.addr,
479                                             desc_bytes);
480  
481          /* Check if frame needs to raise the receive interrupt */
482          if (!(desc.status2 & RX_DESC_STATUS2_RX_INT_CTL)) {
483              s->int_sta |= INT_STA_RX;
484          }
485  
486          /* Increment variables */
487          buf += desc_bytes;
488          bytes_left -= desc_bytes;
489  
490          /* Move to the next descriptor */
491          s->rx_desc_curr = allwinner_sun8i_emac_find_desc(s, &desc, desc.next,
492                                                           AW_SUN8I_EMAC_MIN_PKT_SZ);
493          if (!s->rx_desc_curr) {
494              /* Not enough buffer space available */
495              s->int_sta |= INT_STA_RX_BUF_UA;
496              s->rx_desc_curr = s->rx_desc_head;
497              break;
498          }
499      }
500  
501      /* Report receive DMA is finished */
502      s->rx_ctl1 &= ~RX_CTL1_RX_DMA_START;
503      allwinner_sun8i_emac_update_irq(s);
504  
505      return size;
506  }
507  
allwinner_sun8i_emac_transmit(AwSun8iEmacState * s)508  static void allwinner_sun8i_emac_transmit(AwSun8iEmacState *s)
509  {
510      NetClientState *nc = qemu_get_queue(s->nic);
511      FrameDescriptor desc;
512      size_t bytes = 0;
513      size_t packet_bytes = 0;
514      size_t transmitted = 0;
515      static uint8_t packet_buf[2048];
516  
517      s->tx_desc_curr = allwinner_sun8i_emac_tx_desc(s, &desc);
518  
519      /* Read all transmit descriptors */
520      while (allwinner_sun8i_emac_desc_owned(&desc, 0)) {
521  
522          /* Read from physical memory into packet buffer */
523          bytes = desc.status2 & DESC_STATUS2_BUF_SIZE_MASK;
524          if (bytes + packet_bytes > sizeof(packet_buf)) {
525              desc.status |= TX_DESC_STATUS_LENGTH_ERR;
526              break;
527          }
528          dma_memory_read(&s->dma_as, desc.addr, packet_buf + packet_bytes,
529                          bytes, MEMTXATTRS_UNSPECIFIED);
530          packet_bytes += bytes;
531          desc.status &= ~DESC_STATUS_CTL;
532          allwinner_sun8i_emac_flush_desc(s, &desc, s->tx_desc_curr);
533  
534          /* After the last descriptor, send the packet */
535          if (desc.status2 & TX_DESC_STATUS2_LAST_DESC) {
536              if (desc.status2 & TX_DESC_STATUS2_CHECKSUM_MASK) {
537                  net_checksum_calculate(packet_buf, packet_bytes, CSUM_ALL);
538              }
539  
540              qemu_send_packet(nc, packet_buf, packet_bytes);
541              trace_allwinner_sun8i_emac_transmit(s->tx_desc_curr, desc.addr,
542                                                  bytes);
543  
544              packet_bytes = 0;
545              transmitted++;
546          }
547          s->tx_desc_curr = allwinner_sun8i_emac_next_desc(s, &desc);
548      }
549  
550      /* Raise transmit completed interrupt */
551      if (transmitted > 0) {
552          s->int_sta |= INT_STA_TX;
553          s->tx_ctl1 &= ~TX_CTL1_TX_DMA_START;
554          allwinner_sun8i_emac_update_irq(s);
555      }
556  }
557  
allwinner_sun8i_emac_reset(DeviceState * dev)558  static void allwinner_sun8i_emac_reset(DeviceState *dev)
559  {
560      AwSun8iEmacState *s = AW_SUN8I_EMAC(dev);
561      NetClientState *nc = qemu_get_queue(s->nic);
562  
563      trace_allwinner_sun8i_emac_reset();
564  
565      s->mii_cmd = 0;
566      s->mii_data = 0;
567      s->basic_ctl0 = 0;
568      s->basic_ctl1 = REG_BASIC_CTL_1_RST;
569      s->int_en = 0;
570      s->int_sta = 0;
571      s->frm_flt = 0;
572      s->rx_ctl0 = 0;
573      s->rx_ctl1 = RX_CTL1_RX_MD;
574      s->rx_desc_head = 0;
575      s->rx_desc_curr = 0;
576      s->tx_ctl0 = 0;
577      s->tx_ctl1 = 0;
578      s->tx_desc_head = 0;
579      s->tx_desc_curr = 0;
580      s->tx_flowctl = 0;
581  
582      allwinner_sun8i_emac_mii_reset(s, !nc->link_down);
583  }
584  
allwinner_sun8i_emac_read(void * opaque,hwaddr offset,unsigned size)585  static uint64_t allwinner_sun8i_emac_read(void *opaque, hwaddr offset,
586                                            unsigned size)
587  {
588      AwSun8iEmacState *s = AW_SUN8I_EMAC(opaque);
589      uint64_t value = 0;
590      FrameDescriptor desc;
591  
592      switch (offset) {
593      case REG_BASIC_CTL_0:       /* Basic Control 0 */
594          value = s->basic_ctl0;
595          break;
596      case REG_BASIC_CTL_1:       /* Basic Control 1 */
597          value = s->basic_ctl1;
598          break;
599      case REG_INT_STA:           /* Interrupt Status */
600          value = s->int_sta;
601          break;
602      case REG_INT_EN:            /* Interrupt Enable */
603          value = s->int_en;
604          break;
605      case REG_TX_CTL_0:          /* Transmit Control 0 */
606          value = s->tx_ctl0;
607          break;
608      case REG_TX_CTL_1:          /* Transmit Control 1 */
609          value = s->tx_ctl1;
610          break;
611      case REG_TX_FLOW_CTL:       /* Transmit Flow Control */
612          value = s->tx_flowctl;
613          break;
614      case REG_TX_DMA_DESC_LIST:  /* Transmit Descriptor List Address */
615          value = s->tx_desc_head;
616          break;
617      case REG_RX_CTL_0:          /* Receive Control 0 */
618          value = s->rx_ctl0;
619          break;
620      case REG_RX_CTL_1:          /* Receive Control 1 */
621          value = s->rx_ctl1;
622          break;
623      case REG_RX_DMA_DESC_LIST:  /* Receive Descriptor List Address */
624          value = s->rx_desc_head;
625          break;
626      case REG_FRM_FLT:           /* Receive Frame Filter */
627          value = s->frm_flt;
628          break;
629      case REG_RX_HASH_0:         /* Receive Hash Table 0 */
630      case REG_RX_HASH_1:         /* Receive Hash Table 1 */
631          break;
632      case REG_MII_CMD:           /* Management Interface Command */
633          value = s->mii_cmd;
634          break;
635      case REG_MII_DATA:          /* Management Interface Data */
636          value = s->mii_data;
637          break;
638      case REG_ADDR_HIGH:         /* MAC Address High */
639          value = lduw_le_p(s->conf.macaddr.a + 4);
640          break;
641      case REG_ADDR_LOW:          /* MAC Address Low */
642          value = ldl_le_p(s->conf.macaddr.a);
643          break;
644      case REG_TX_DMA_STA:        /* Transmit DMA Status */
645          break;
646      case REG_TX_CUR_DESC:       /* Transmit Current Descriptor */
647          value = s->tx_desc_curr;
648          break;
649      case REG_TX_CUR_BUF:        /* Transmit Current Buffer */
650          if (s->tx_desc_curr != 0) {
651              allwinner_sun8i_emac_get_desc(s, &desc, s->tx_desc_curr);
652              value = desc.addr;
653          } else {
654              value = 0;
655          }
656          break;
657      case REG_RX_DMA_STA:        /* Receive DMA Status */
658          break;
659      case REG_RX_CUR_DESC:       /* Receive Current Descriptor */
660          value = s->rx_desc_curr;
661          break;
662      case REG_RX_CUR_BUF:        /* Receive Current Buffer */
663          if (s->rx_desc_curr != 0) {
664              allwinner_sun8i_emac_get_desc(s, &desc, s->rx_desc_curr);
665              value = desc.addr;
666          } else {
667              value = 0;
668          }
669          break;
670      case REG_RGMII_STA:         /* RGMII Status */
671          break;
672      default:
673          qemu_log_mask(LOG_UNIMP, "allwinner-h3-emac: read access to unknown "
674                                   "EMAC register 0x" HWADDR_FMT_plx "\n",
675                                    offset);
676      }
677  
678      trace_allwinner_sun8i_emac_read(offset, value);
679      return value;
680  }
681  
allwinner_sun8i_emac_write(void * opaque,hwaddr offset,uint64_t value,unsigned size)682  static void allwinner_sun8i_emac_write(void *opaque, hwaddr offset,
683                                         uint64_t value, unsigned size)
684  {
685      AwSun8iEmacState *s = AW_SUN8I_EMAC(opaque);
686      NetClientState *nc = qemu_get_queue(s->nic);
687  
688      trace_allwinner_sun8i_emac_write(offset, value);
689  
690      switch (offset) {
691      case REG_BASIC_CTL_0:       /* Basic Control 0 */
692          s->basic_ctl0 = value;
693          break;
694      case REG_BASIC_CTL_1:       /* Basic Control 1 */
695          if (value & BASIC_CTL1_SOFTRST) {
696              allwinner_sun8i_emac_reset(DEVICE(s));
697              value &= ~BASIC_CTL1_SOFTRST;
698          }
699          s->basic_ctl1 = value;
700          if (allwinner_sun8i_emac_can_receive(nc)) {
701              qemu_flush_queued_packets(nc);
702          }
703          break;
704      case REG_INT_STA:           /* Interrupt Status */
705          s->int_sta &= ~value;
706          allwinner_sun8i_emac_update_irq(s);
707          break;
708      case REG_INT_EN:            /* Interrupt Enable */
709          s->int_en = value;
710          allwinner_sun8i_emac_update_irq(s);
711          break;
712      case REG_TX_CTL_0:          /* Transmit Control 0 */
713          s->tx_ctl0 = value;
714          break;
715      case REG_TX_CTL_1:          /* Transmit Control 1 */
716          s->tx_ctl1 = value;
717          if (value & TX_CTL1_TX_DMA_EN) {
718              allwinner_sun8i_emac_transmit(s);
719          }
720          break;
721      case REG_TX_FLOW_CTL:       /* Transmit Flow Control */
722          s->tx_flowctl = value;
723          break;
724      case REG_TX_DMA_DESC_LIST:  /* Transmit Descriptor List Address */
725          s->tx_desc_head = value;
726          s->tx_desc_curr = value;
727          break;
728      case REG_RX_CTL_0:          /* Receive Control 0 */
729          s->rx_ctl0 = value;
730          break;
731      case REG_RX_CTL_1:          /* Receive Control 1 */
732          s->rx_ctl1 = value | RX_CTL1_RX_MD;
733          if ((value & RX_CTL1_RX_DMA_EN) &&
734               allwinner_sun8i_emac_can_receive(nc)) {
735              qemu_flush_queued_packets(nc);
736          }
737          break;
738      case REG_RX_DMA_DESC_LIST:  /* Receive Descriptor List Address */
739          s->rx_desc_head = value;
740          s->rx_desc_curr = value;
741          break;
742      case REG_FRM_FLT:           /* Receive Frame Filter */
743          s->frm_flt = value;
744          break;
745      case REG_RX_HASH_0:         /* Receive Hash Table 0 */
746      case REG_RX_HASH_1:         /* Receive Hash Table 1 */
747          break;
748      case REG_MII_CMD:           /* Management Interface Command */
749          s->mii_cmd = value & ~MII_CMD_PHY_BUSY;
750          allwinner_sun8i_emac_mii_cmd(s);
751          break;
752      case REG_MII_DATA:          /* Management Interface Data */
753          s->mii_data = value;
754          break;
755      case REG_ADDR_HIGH:         /* MAC Address High */
756          stw_le_p(s->conf.macaddr.a + 4, value);
757          break;
758      case REG_ADDR_LOW:          /* MAC Address Low */
759          stl_le_p(s->conf.macaddr.a, value);
760          break;
761      case REG_TX_DMA_STA:        /* Transmit DMA Status */
762      case REG_TX_CUR_DESC:       /* Transmit Current Descriptor */
763      case REG_TX_CUR_BUF:        /* Transmit Current Buffer */
764      case REG_RX_DMA_STA:        /* Receive DMA Status */
765      case REG_RX_CUR_DESC:       /* Receive Current Descriptor */
766      case REG_RX_CUR_BUF:        /* Receive Current Buffer */
767      case REG_RGMII_STA:         /* RGMII Status */
768          break;
769      default:
770          qemu_log_mask(LOG_UNIMP, "allwinner-h3-emac: write access to unknown "
771                                   "EMAC register 0x" HWADDR_FMT_plx "\n",
772                                    offset);
773      }
774  }
775  
allwinner_sun8i_emac_set_link(NetClientState * nc)776  static void allwinner_sun8i_emac_set_link(NetClientState *nc)
777  {
778      AwSun8iEmacState *s = qemu_get_nic_opaque(nc);
779  
780      trace_allwinner_sun8i_emac_set_link(!nc->link_down);
781      allwinner_sun8i_emac_mii_set_link(s, !nc->link_down);
782  }
783  
784  static const MemoryRegionOps allwinner_sun8i_emac_mem_ops = {
785      .read = allwinner_sun8i_emac_read,
786      .write = allwinner_sun8i_emac_write,
787      .endianness = DEVICE_NATIVE_ENDIAN,
788      .valid = {
789          .min_access_size = 4,
790          .max_access_size = 4,
791      },
792      .impl.min_access_size = 4,
793  };
794  
795  static NetClientInfo net_allwinner_sun8i_emac_info = {
796      .type = NET_CLIENT_DRIVER_NIC,
797      .size = sizeof(NICState),
798      .can_receive = allwinner_sun8i_emac_can_receive,
799      .receive = allwinner_sun8i_emac_receive,
800      .link_status_changed = allwinner_sun8i_emac_set_link,
801  };
802  
allwinner_sun8i_emac_init(Object * obj)803  static void allwinner_sun8i_emac_init(Object *obj)
804  {
805      SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
806      AwSun8iEmacState *s = AW_SUN8I_EMAC(obj);
807  
808      memory_region_init_io(&s->iomem, OBJECT(s), &allwinner_sun8i_emac_mem_ops,
809                             s, TYPE_AW_SUN8I_EMAC, 64 * KiB);
810      sysbus_init_mmio(sbd, &s->iomem);
811      sysbus_init_irq(sbd, &s->irq);
812  }
813  
allwinner_sun8i_emac_realize(DeviceState * dev,Error ** errp)814  static void allwinner_sun8i_emac_realize(DeviceState *dev, Error **errp)
815  {
816      AwSun8iEmacState *s = AW_SUN8I_EMAC(dev);
817  
818      if (!s->dma_mr) {
819          error_setg(errp, TYPE_AW_SUN8I_EMAC " 'dma-memory' link not set");
820          return;
821      }
822  
823      address_space_init(&s->dma_as, s->dma_mr, "emac-dma");
824  
825      qemu_macaddr_default_if_unset(&s->conf.macaddr);
826      s->nic = qemu_new_nic(&net_allwinner_sun8i_emac_info, &s->conf,
827                            object_get_typename(OBJECT(dev)), dev->id,
828                            &dev->mem_reentrancy_guard, s);
829      qemu_format_nic_info_str(qemu_get_queue(s->nic), s->conf.macaddr.a);
830  }
831  
832  static Property allwinner_sun8i_emac_properties[] = {
833      DEFINE_NIC_PROPERTIES(AwSun8iEmacState, conf),
834      DEFINE_PROP_UINT8("phy-addr", AwSun8iEmacState, mii_phy_addr, 0),
835      DEFINE_PROP_LINK("dma-memory", AwSun8iEmacState, dma_mr,
836                       TYPE_MEMORY_REGION, MemoryRegion *),
837      DEFINE_PROP_END_OF_LIST(),
838  };
839  
allwinner_sun8i_emac_post_load(void * opaque,int version_id)840  static int allwinner_sun8i_emac_post_load(void *opaque, int version_id)
841  {
842      AwSun8iEmacState *s = opaque;
843  
844      allwinner_sun8i_emac_set_link(qemu_get_queue(s->nic));
845  
846      return 0;
847  }
848  
849  static const VMStateDescription vmstate_aw_emac = {
850      .name = "allwinner-sun8i-emac",
851      .version_id = 1,
852      .minimum_version_id = 1,
853      .post_load = allwinner_sun8i_emac_post_load,
854      .fields = (const VMStateField[]) {
855          VMSTATE_UINT8(mii_phy_addr, AwSun8iEmacState),
856          VMSTATE_UINT32(mii_cmd, AwSun8iEmacState),
857          VMSTATE_UINT32(mii_data, AwSun8iEmacState),
858          VMSTATE_UINT32(mii_cr, AwSun8iEmacState),
859          VMSTATE_UINT32(mii_st, AwSun8iEmacState),
860          VMSTATE_UINT32(mii_adv, AwSun8iEmacState),
861          VMSTATE_UINT32(basic_ctl0, AwSun8iEmacState),
862          VMSTATE_UINT32(basic_ctl1, AwSun8iEmacState),
863          VMSTATE_UINT32(int_en, AwSun8iEmacState),
864          VMSTATE_UINT32(int_sta, AwSun8iEmacState),
865          VMSTATE_UINT32(frm_flt, AwSun8iEmacState),
866          VMSTATE_UINT32(rx_ctl0, AwSun8iEmacState),
867          VMSTATE_UINT32(rx_ctl1, AwSun8iEmacState),
868          VMSTATE_UINT32(rx_desc_head, AwSun8iEmacState),
869          VMSTATE_UINT32(rx_desc_curr, AwSun8iEmacState),
870          VMSTATE_UINT32(tx_ctl0, AwSun8iEmacState),
871          VMSTATE_UINT32(tx_ctl1, AwSun8iEmacState),
872          VMSTATE_UINT32(tx_desc_head, AwSun8iEmacState),
873          VMSTATE_UINT32(tx_desc_curr, AwSun8iEmacState),
874          VMSTATE_UINT32(tx_flowctl, AwSun8iEmacState),
875          VMSTATE_END_OF_LIST()
876      }
877  };
878  
allwinner_sun8i_emac_class_init(ObjectClass * klass,void * data)879  static void allwinner_sun8i_emac_class_init(ObjectClass *klass, void *data)
880  {
881      DeviceClass *dc = DEVICE_CLASS(klass);
882  
883      dc->realize = allwinner_sun8i_emac_realize;
884      device_class_set_legacy_reset(dc, allwinner_sun8i_emac_reset);
885      dc->vmsd = &vmstate_aw_emac;
886      device_class_set_props(dc, allwinner_sun8i_emac_properties);
887  }
888  
889  static const TypeInfo allwinner_sun8i_emac_info = {
890      .name           = TYPE_AW_SUN8I_EMAC,
891      .parent         = TYPE_SYS_BUS_DEVICE,
892      .instance_size  = sizeof(AwSun8iEmacState),
893      .instance_init  = allwinner_sun8i_emac_init,
894      .class_init     = allwinner_sun8i_emac_class_init,
895  };
896  
allwinner_sun8i_emac_register_types(void)897  static void allwinner_sun8i_emac_register_types(void)
898  {
899      type_register_static(&allwinner_sun8i_emac_info);
900  }
901  
902  type_init(allwinner_sun8i_emac_register_types)
903