xref: /openbmc/qemu/hw/net/tulip.c (revision 28ae3179fc52d2e4d870b635c4a412aab99759e7)
134ea023dSSven Schnelle /*
234ea023dSSven Schnelle  * QEMU TULIP Emulation
334ea023dSSven Schnelle  *
434ea023dSSven Schnelle  * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org>
534ea023dSSven Schnelle  *
634ea023dSSven Schnelle  * This work is licensed under the GNU GPL license version 2 or later.
734ea023dSSven Schnelle  */
834ea023dSSven Schnelle 
934ea023dSSven Schnelle #include "qemu/osdep.h"
1034ea023dSSven Schnelle #include "qemu/log.h"
1134ea023dSSven Schnelle #include "hw/irq.h"
12edf5ca5dSMarkus Armbruster #include "hw/pci/pci_device.h"
1334ea023dSSven Schnelle #include "hw/qdev-properties.h"
1434ea023dSSven Schnelle #include "hw/nvram/eeprom93xx.h"
1534ea023dSSven Schnelle #include "migration/vmstate.h"
1634ea023dSSven Schnelle #include "sysemu/sysemu.h"
1734ea023dSSven Schnelle #include "tulip.h"
1834ea023dSSven Schnelle #include "trace.h"
1934ea023dSSven Schnelle #include "net/eth.h"
2034ea023dSSven Schnelle 
2157af4d7fSEduardo Habkost struct TULIPState {
2234ea023dSSven Schnelle     PCIDevice dev;
2334ea023dSSven Schnelle     MemoryRegion io;
2434ea023dSSven Schnelle     MemoryRegion memory;
2534ea023dSSven Schnelle     NICConf c;
2634ea023dSSven Schnelle     qemu_irq irq;
2734ea023dSSven Schnelle     NICState *nic;
2834ea023dSSven Schnelle     eeprom_t *eeprom;
2934ea023dSSven Schnelle     uint32_t csr[16];
3034ea023dSSven Schnelle 
3134ea023dSSven Schnelle     /* state for MII */
3234ea023dSSven Schnelle     uint32_t old_csr9;
3334ea023dSSven Schnelle     uint32_t mii_word;
3434ea023dSSven Schnelle     uint32_t mii_bitcnt;
3534ea023dSSven Schnelle 
3634ea023dSSven Schnelle     hwaddr current_rx_desc;
3734ea023dSSven Schnelle     hwaddr current_tx_desc;
3834ea023dSSven Schnelle 
3934ea023dSSven Schnelle     uint8_t rx_frame[2048];
4034ea023dSSven Schnelle     uint8_t tx_frame[2048];
4134ea023dSSven Schnelle     uint16_t tx_frame_len;
4234ea023dSSven Schnelle     uint16_t rx_frame_len;
4334ea023dSSven Schnelle     uint16_t rx_frame_size;
4434ea023dSSven Schnelle 
4534ea023dSSven Schnelle     uint32_t rx_status;
4634ea023dSSven Schnelle     uint8_t filter[16][6];
4757af4d7fSEduardo Habkost };
4834ea023dSSven Schnelle 
4934ea023dSSven Schnelle static const VMStateDescription vmstate_pci_tulip = {
5034ea023dSSven Schnelle     .name = "tulip",
511de81b42SRichard Henderson     .fields = (const VMStateField[]) {
5234ea023dSSven Schnelle         VMSTATE_PCI_DEVICE(dev, TULIPState),
5334ea023dSSven Schnelle         VMSTATE_UINT32_ARRAY(csr, TULIPState, 16),
5434ea023dSSven Schnelle         VMSTATE_UINT32(old_csr9, TULIPState),
5534ea023dSSven Schnelle         VMSTATE_UINT32(mii_word, TULIPState),
5634ea023dSSven Schnelle         VMSTATE_UINT32(mii_bitcnt, TULIPState),
5734ea023dSSven Schnelle         VMSTATE_UINT64(current_rx_desc, TULIPState),
5834ea023dSSven Schnelle         VMSTATE_UINT64(current_tx_desc, TULIPState),
5934ea023dSSven Schnelle         VMSTATE_BUFFER(rx_frame, TULIPState),
6034ea023dSSven Schnelle         VMSTATE_BUFFER(tx_frame, TULIPState),
6134ea023dSSven Schnelle         VMSTATE_UINT16(rx_frame_len, TULIPState),
6234ea023dSSven Schnelle         VMSTATE_UINT16(tx_frame_len, TULIPState),
6334ea023dSSven Schnelle         VMSTATE_UINT16(rx_frame_size, TULIPState),
6434ea023dSSven Schnelle         VMSTATE_UINT32(rx_status, TULIPState),
6534ea023dSSven Schnelle         VMSTATE_UINT8_2DARRAY(filter, TULIPState, 16, 6),
6634ea023dSSven Schnelle         VMSTATE_END_OF_LIST()
6734ea023dSSven Schnelle     }
6834ea023dSSven Schnelle };
6934ea023dSSven Schnelle 
tulip_desc_read(TULIPState * s,hwaddr p,struct tulip_descriptor * desc)7034ea023dSSven Schnelle static void tulip_desc_read(TULIPState *s, hwaddr p,
7134ea023dSSven Schnelle         struct tulip_descriptor *desc)
7234ea023dSSven Schnelle {
7336a894aeSZheyu Ma     const MemTxAttrs attrs = { .memory = true };
74398f9a84SPhilippe Mathieu-Daudé 
7534ea023dSSven Schnelle     if (s->csr[0] & CSR0_DBO) {
764a63054bSPhilippe Mathieu-Daudé         ldl_be_pci_dma(&s->dev, p, &desc->status, attrs);
774a63054bSPhilippe Mathieu-Daudé         ldl_be_pci_dma(&s->dev, p + 4, &desc->control, attrs);
784a63054bSPhilippe Mathieu-Daudé         ldl_be_pci_dma(&s->dev, p + 8, &desc->buf_addr1, attrs);
794a63054bSPhilippe Mathieu-Daudé         ldl_be_pci_dma(&s->dev, p + 12, &desc->buf_addr2, attrs);
8034ea023dSSven Schnelle     } else {
814a63054bSPhilippe Mathieu-Daudé         ldl_le_pci_dma(&s->dev, p, &desc->status, attrs);
824a63054bSPhilippe Mathieu-Daudé         ldl_le_pci_dma(&s->dev, p + 4, &desc->control, attrs);
834a63054bSPhilippe Mathieu-Daudé         ldl_le_pci_dma(&s->dev, p + 8, &desc->buf_addr1, attrs);
844a63054bSPhilippe Mathieu-Daudé         ldl_le_pci_dma(&s->dev, p + 12, &desc->buf_addr2, attrs);
8534ea023dSSven Schnelle     }
8634ea023dSSven Schnelle }
8734ea023dSSven Schnelle 
tulip_desc_write(TULIPState * s,hwaddr p,struct tulip_descriptor * desc)8834ea023dSSven Schnelle static void tulip_desc_write(TULIPState *s, hwaddr p,
8934ea023dSSven Schnelle         struct tulip_descriptor *desc)
9034ea023dSSven Schnelle {
9136a894aeSZheyu Ma     const MemTxAttrs attrs = { .memory = true };
92a423a1b5SPhilippe Mathieu-Daudé 
9334ea023dSSven Schnelle     if (s->csr[0] & CSR0_DBO) {
94a423a1b5SPhilippe Mathieu-Daudé         stl_be_pci_dma(&s->dev, p, desc->status, attrs);
95a423a1b5SPhilippe Mathieu-Daudé         stl_be_pci_dma(&s->dev, p + 4, desc->control, attrs);
96a423a1b5SPhilippe Mathieu-Daudé         stl_be_pci_dma(&s->dev, p + 8, desc->buf_addr1, attrs);
97a423a1b5SPhilippe Mathieu-Daudé         stl_be_pci_dma(&s->dev, p + 12, desc->buf_addr2, attrs);
9834ea023dSSven Schnelle     } else {
99a423a1b5SPhilippe Mathieu-Daudé         stl_le_pci_dma(&s->dev, p, desc->status, attrs);
100a423a1b5SPhilippe Mathieu-Daudé         stl_le_pci_dma(&s->dev, p + 4, desc->control, attrs);
101a423a1b5SPhilippe Mathieu-Daudé         stl_le_pci_dma(&s->dev, p + 8, desc->buf_addr1, attrs);
102a423a1b5SPhilippe Mathieu-Daudé         stl_le_pci_dma(&s->dev, p + 12, desc->buf_addr2, attrs);
10334ea023dSSven Schnelle     }
10434ea023dSSven Schnelle }
10534ea023dSSven Schnelle 
tulip_update_int(TULIPState * s)10634ea023dSSven Schnelle static void tulip_update_int(TULIPState *s)
10734ea023dSSven Schnelle {
10834ea023dSSven Schnelle     uint32_t ie = s->csr[5] & s->csr[7];
10934ea023dSSven Schnelle     bool assert = false;
11034ea023dSSven Schnelle 
11134ea023dSSven Schnelle     s->csr[5] &= ~(CSR5_AIS | CSR5_NIS);
11234ea023dSSven Schnelle 
11334ea023dSSven Schnelle     if (ie & (CSR5_TI | CSR5_TU | CSR5_RI | CSR5_GTE | CSR5_ERI)) {
11434ea023dSSven Schnelle         s->csr[5] |= CSR5_NIS;
11534ea023dSSven Schnelle     }
11634ea023dSSven Schnelle 
11734ea023dSSven Schnelle     if (ie & (CSR5_LC | CSR5_GPI | CSR5_FBE | CSR5_LNF | CSR5_ETI | CSR5_RWT |
11834ea023dSSven Schnelle               CSR5_RPS | CSR5_RU | CSR5_UNF | CSR5_LNP_ANC | CSR5_TJT |
11934ea023dSSven Schnelle               CSR5_TPS)) {
12034ea023dSSven Schnelle         s->csr[5] |= CSR5_AIS;
12134ea023dSSven Schnelle     }
12234ea023dSSven Schnelle 
12334ea023dSSven Schnelle     assert = s->csr[5] & s->csr[7] & (CSR5_AIS | CSR5_NIS);
12434ea023dSSven Schnelle     trace_tulip_irq(s->csr[5], s->csr[7], assert ? "assert" : "deassert");
12534ea023dSSven Schnelle     qemu_set_irq(s->irq, assert);
12634ea023dSSven Schnelle }
12734ea023dSSven Schnelle 
tulip_rx_stopped(TULIPState * s)12834ea023dSSven Schnelle static bool tulip_rx_stopped(TULIPState *s)
12934ea023dSSven Schnelle {
13034ea023dSSven Schnelle     return ((s->csr[5] >> CSR5_RS_SHIFT) & CSR5_RS_MASK) == CSR5_RS_STOPPED;
13134ea023dSSven Schnelle }
13234ea023dSSven Schnelle 
tulip_dump_tx_descriptor(TULIPState * s,struct tulip_descriptor * desc)13334ea023dSSven Schnelle static void tulip_dump_tx_descriptor(TULIPState *s,
13434ea023dSSven Schnelle         struct tulip_descriptor *desc)
13534ea023dSSven Schnelle {
13634ea023dSSven Schnelle     trace_tulip_descriptor("TX ", s->current_tx_desc,
13734ea023dSSven Schnelle                 desc->status, desc->control >> 22,
13834ea023dSSven Schnelle                 desc->control & 0x7ff, (desc->control >> 11) & 0x7ff,
13934ea023dSSven Schnelle                 desc->buf_addr1, desc->buf_addr2);
14034ea023dSSven Schnelle }
14134ea023dSSven Schnelle 
tulip_dump_rx_descriptor(TULIPState * s,struct tulip_descriptor * desc)14234ea023dSSven Schnelle static void tulip_dump_rx_descriptor(TULIPState *s,
14334ea023dSSven Schnelle         struct tulip_descriptor *desc)
14434ea023dSSven Schnelle {
14534ea023dSSven Schnelle     trace_tulip_descriptor("RX ", s->current_rx_desc,
14634ea023dSSven Schnelle                 desc->status, desc->control >> 22,
14734ea023dSSven Schnelle                 desc->control & 0x7ff, (desc->control >> 11) & 0x7ff,
14834ea023dSSven Schnelle                 desc->buf_addr1, desc->buf_addr2);
14934ea023dSSven Schnelle }
15034ea023dSSven Schnelle 
tulip_next_rx_descriptor(TULIPState * s,struct tulip_descriptor * desc)15134ea023dSSven Schnelle static void tulip_next_rx_descriptor(TULIPState *s,
15234ea023dSSven Schnelle     struct tulip_descriptor *desc)
15334ea023dSSven Schnelle {
15434ea023dSSven Schnelle     if (desc->control & RDES1_RER) {
15534ea023dSSven Schnelle         s->current_rx_desc = s->csr[3];
15634ea023dSSven Schnelle     } else if (desc->control & RDES1_RCH) {
15734ea023dSSven Schnelle         s->current_rx_desc = desc->buf_addr2;
15834ea023dSSven Schnelle     } else {
15934ea023dSSven Schnelle         s->current_rx_desc += sizeof(struct tulip_descriptor) +
16034ea023dSSven Schnelle                 (((s->csr[0] >> CSR0_DSL_SHIFT) & CSR0_DSL_MASK) << 2);
16134ea023dSSven Schnelle     }
16234ea023dSSven Schnelle     s->current_rx_desc &= ~3ULL;
16334ea023dSSven Schnelle }
16434ea023dSSven Schnelle 
tulip_copy_rx_bytes(TULIPState * s,struct tulip_descriptor * desc)16534ea023dSSven Schnelle static void tulip_copy_rx_bytes(TULIPState *s, struct tulip_descriptor *desc)
16634ea023dSSven Schnelle {
16734ea023dSSven Schnelle     int len1 = (desc->control >> RDES1_BUF1_SIZE_SHIFT) & RDES1_BUF1_SIZE_MASK;
16834ea023dSSven Schnelle     int len2 = (desc->control >> RDES1_BUF2_SIZE_SHIFT) & RDES1_BUF2_SIZE_MASK;
16934ea023dSSven Schnelle     int len;
17034ea023dSSven Schnelle 
17134ea023dSSven Schnelle     if (s->rx_frame_len && len1) {
17234ea023dSSven Schnelle         if (s->rx_frame_len > len1) {
17334ea023dSSven Schnelle             len = len1;
17434ea023dSSven Schnelle         } else {
17534ea023dSSven Schnelle             len = s->rx_frame_len;
17634ea023dSSven Schnelle         }
1778ffb7265SPrasad J Pandit 
17834ea023dSSven Schnelle         pci_dma_write(&s->dev, desc->buf_addr1, s->rx_frame +
17934ea023dSSven Schnelle             (s->rx_frame_size - s->rx_frame_len), len);
18034ea023dSSven Schnelle         s->rx_frame_len -= len;
18134ea023dSSven Schnelle     }
18234ea023dSSven Schnelle 
18334ea023dSSven Schnelle     if (s->rx_frame_len && len2) {
18434ea023dSSven Schnelle         if (s->rx_frame_len > len2) {
18534ea023dSSven Schnelle             len = len2;
18634ea023dSSven Schnelle         } else {
18734ea023dSSven Schnelle             len = s->rx_frame_len;
18834ea023dSSven Schnelle         }
1898ffb7265SPrasad J Pandit 
19034ea023dSSven Schnelle         pci_dma_write(&s->dev, desc->buf_addr2, s->rx_frame +
19134ea023dSSven Schnelle             (s->rx_frame_size - s->rx_frame_len), len);
19234ea023dSSven Schnelle         s->rx_frame_len -= len;
19334ea023dSSven Schnelle     }
19434ea023dSSven Schnelle }
19534ea023dSSven Schnelle 
tulip_filter_address(TULIPState * s,const uint8_t * addr)19634ea023dSSven Schnelle static bool tulip_filter_address(TULIPState *s, const uint8_t *addr)
19734ea023dSSven Schnelle {
19834ea023dSSven Schnelle     static const char broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
19934ea023dSSven Schnelle     bool ret = false;
20034ea023dSSven Schnelle     int i;
20134ea023dSSven Schnelle 
20234ea023dSSven Schnelle     for (i = 0; i < 16 && ret == false; i++) {
20334ea023dSSven Schnelle         if (!memcmp(&s->filter[i], addr, ETH_ALEN)) {
20434ea023dSSven Schnelle             ret = true;
20534ea023dSSven Schnelle         }
20634ea023dSSven Schnelle     }
20734ea023dSSven Schnelle 
20834ea023dSSven Schnelle     if (!memcmp(addr, broadcast, ETH_ALEN)) {
20934ea023dSSven Schnelle         return true;
21034ea023dSSven Schnelle     }
21134ea023dSSven Schnelle 
21234ea023dSSven Schnelle     if (s->csr[6] & (CSR6_PR | CSR6_RA)) {
21334ea023dSSven Schnelle         /* Promiscuous mode enabled */
21434ea023dSSven Schnelle         s->rx_status |= RDES0_FF;
21534ea023dSSven Schnelle         return true;
21634ea023dSSven Schnelle     }
21734ea023dSSven Schnelle 
21834ea023dSSven Schnelle     if ((s->csr[6] & CSR6_PM) && (addr[0] & 1)) {
21934ea023dSSven Schnelle         /* Pass all Multicast enabled */
22034ea023dSSven Schnelle         s->rx_status |= RDES0_MF;
22134ea023dSSven Schnelle         return true;
22234ea023dSSven Schnelle     }
22334ea023dSSven Schnelle 
22434ea023dSSven Schnelle     if (s->csr[6] & CSR6_IF) {
22534ea023dSSven Schnelle         ret ^= true;
22634ea023dSSven Schnelle     }
22734ea023dSSven Schnelle     return ret;
22834ea023dSSven Schnelle }
22934ea023dSSven Schnelle 
tulip_receive(TULIPState * s,const uint8_t * buf,size_t size)23034ea023dSSven Schnelle static ssize_t tulip_receive(TULIPState *s, const uint8_t *buf, size_t size)
23134ea023dSSven Schnelle {
23234ea023dSSven Schnelle     struct tulip_descriptor desc;
23334ea023dSSven Schnelle 
23434ea023dSSven Schnelle     trace_tulip_receive(buf, size);
23534ea023dSSven Schnelle 
2368ffb7265SPrasad J Pandit     if (size < 14 || size > sizeof(s->rx_frame) - 4
2378ffb7265SPrasad J Pandit         || s->rx_frame_len || tulip_rx_stopped(s)) {
23834ea023dSSven Schnelle         return 0;
23934ea023dSSven Schnelle     }
24034ea023dSSven Schnelle 
24134ea023dSSven Schnelle     if (!tulip_filter_address(s, buf)) {
24234ea023dSSven Schnelle         return size;
24334ea023dSSven Schnelle     }
24434ea023dSSven Schnelle 
24534ea023dSSven Schnelle     do {
24634ea023dSSven Schnelle         tulip_desc_read(s, s->current_rx_desc, &desc);
24734ea023dSSven Schnelle         tulip_dump_rx_descriptor(s, &desc);
24834ea023dSSven Schnelle 
24934ea023dSSven Schnelle         if (!(desc.status & RDES0_OWN)) {
25034ea023dSSven Schnelle             s->csr[5] |= CSR5_RU;
25134ea023dSSven Schnelle             tulip_update_int(s);
25234ea023dSSven Schnelle             return s->rx_frame_size - s->rx_frame_len;
25334ea023dSSven Schnelle         }
25434ea023dSSven Schnelle         desc.status = 0;
25534ea023dSSven Schnelle 
25634ea023dSSven Schnelle         if (!s->rx_frame_len) {
25734ea023dSSven Schnelle             s->rx_frame_size = size + 4;
25834ea023dSSven Schnelle             s->rx_status = RDES0_LS |
25934ea023dSSven Schnelle                  ((s->rx_frame_size & RDES0_FL_MASK) << RDES0_FL_SHIFT);
26034ea023dSSven Schnelle             desc.status |= RDES0_FS;
26134ea023dSSven Schnelle             memcpy(s->rx_frame, buf, size);
26234ea023dSSven Schnelle             s->rx_frame_len = s->rx_frame_size;
26334ea023dSSven Schnelle         }
26434ea023dSSven Schnelle 
26534ea023dSSven Schnelle         tulip_copy_rx_bytes(s, &desc);
26634ea023dSSven Schnelle 
26734ea023dSSven Schnelle         if (!s->rx_frame_len) {
26834ea023dSSven Schnelle             desc.status |= s->rx_status;
26934ea023dSSven Schnelle             s->csr[5] |= CSR5_RI;
27034ea023dSSven Schnelle             tulip_update_int(s);
27134ea023dSSven Schnelle         }
27234ea023dSSven Schnelle         tulip_dump_rx_descriptor(s, &desc);
27334ea023dSSven Schnelle         tulip_desc_write(s, s->current_rx_desc, &desc);
27434ea023dSSven Schnelle         tulip_next_rx_descriptor(s, &desc);
27534ea023dSSven Schnelle     } while (s->rx_frame_len);
27634ea023dSSven Schnelle     return size;
27734ea023dSSven Schnelle }
27834ea023dSSven Schnelle 
tulip_receive_nc(NetClientState * nc,const uint8_t * buf,size_t size)27934ea023dSSven Schnelle static ssize_t tulip_receive_nc(NetClientState *nc,
28034ea023dSSven Schnelle                              const uint8_t *buf, size_t size)
28134ea023dSSven Schnelle {
28234ea023dSSven Schnelle     return tulip_receive(qemu_get_nic_opaque(nc), buf, size);
28334ea023dSSven Schnelle }
28434ea023dSSven Schnelle 
28534ea023dSSven Schnelle static NetClientInfo net_tulip_info = {
28634ea023dSSven Schnelle     .type = NET_CLIENT_DRIVER_NIC,
28734ea023dSSven Schnelle     .size = sizeof(NICState),
28834ea023dSSven Schnelle     .receive = tulip_receive_nc,
28934ea023dSSven Schnelle };
29034ea023dSSven Schnelle 
tulip_reg_name(const hwaddr addr)29134ea023dSSven Schnelle static const char *tulip_reg_name(const hwaddr addr)
29234ea023dSSven Schnelle {
29334ea023dSSven Schnelle     switch (addr) {
29434ea023dSSven Schnelle     case CSR(0):
29534ea023dSSven Schnelle         return "CSR0";
29634ea023dSSven Schnelle 
29734ea023dSSven Schnelle     case CSR(1):
29834ea023dSSven Schnelle         return "CSR1";
29934ea023dSSven Schnelle 
30034ea023dSSven Schnelle     case CSR(2):
30134ea023dSSven Schnelle         return "CSR2";
30234ea023dSSven Schnelle 
30334ea023dSSven Schnelle     case CSR(3):
30434ea023dSSven Schnelle         return "CSR3";
30534ea023dSSven Schnelle 
30634ea023dSSven Schnelle     case CSR(4):
30734ea023dSSven Schnelle         return "CSR4";
30834ea023dSSven Schnelle 
30934ea023dSSven Schnelle     case CSR(5):
31034ea023dSSven Schnelle         return "CSR5";
31134ea023dSSven Schnelle 
31234ea023dSSven Schnelle     case CSR(6):
31334ea023dSSven Schnelle         return "CSR6";
31434ea023dSSven Schnelle 
31534ea023dSSven Schnelle     case CSR(7):
31634ea023dSSven Schnelle         return "CSR7";
31734ea023dSSven Schnelle 
31834ea023dSSven Schnelle     case CSR(8):
31934ea023dSSven Schnelle         return "CSR8";
32034ea023dSSven Schnelle 
32134ea023dSSven Schnelle     case CSR(9):
32234ea023dSSven Schnelle         return "CSR9";
32334ea023dSSven Schnelle 
32434ea023dSSven Schnelle     case CSR(10):
32534ea023dSSven Schnelle         return "CSR10";
32634ea023dSSven Schnelle 
32734ea023dSSven Schnelle     case CSR(11):
32834ea023dSSven Schnelle         return "CSR11";
32934ea023dSSven Schnelle 
33034ea023dSSven Schnelle     case CSR(12):
33134ea023dSSven Schnelle         return "CSR12";
33234ea023dSSven Schnelle 
33334ea023dSSven Schnelle     case CSR(13):
33434ea023dSSven Schnelle         return "CSR13";
33534ea023dSSven Schnelle 
33634ea023dSSven Schnelle     case CSR(14):
33734ea023dSSven Schnelle         return "CSR14";
33834ea023dSSven Schnelle 
33934ea023dSSven Schnelle     case CSR(15):
34034ea023dSSven Schnelle         return "CSR15";
34134ea023dSSven Schnelle 
34234ea023dSSven Schnelle     default:
34334ea023dSSven Schnelle         break;
34434ea023dSSven Schnelle     }
34534ea023dSSven Schnelle     return "";
34634ea023dSSven Schnelle }
34734ea023dSSven Schnelle 
tulip_rx_state_name(int state)34834ea023dSSven Schnelle static const char *tulip_rx_state_name(int state)
34934ea023dSSven Schnelle {
35034ea023dSSven Schnelle     switch (state) {
35134ea023dSSven Schnelle     case CSR5_RS_STOPPED:
35234ea023dSSven Schnelle         return "STOPPED";
35334ea023dSSven Schnelle 
35434ea023dSSven Schnelle     case CSR5_RS_RUNNING_FETCH:
35534ea023dSSven Schnelle         return "RUNNING/FETCH";
35634ea023dSSven Schnelle 
35734ea023dSSven Schnelle     case CSR5_RS_RUNNING_CHECK_EOR:
35834ea023dSSven Schnelle         return "RUNNING/CHECK EOR";
35934ea023dSSven Schnelle 
36034ea023dSSven Schnelle     case CSR5_RS_RUNNING_WAIT_RECEIVE:
36134ea023dSSven Schnelle         return "WAIT RECEIVE";
36234ea023dSSven Schnelle 
36334ea023dSSven Schnelle     case CSR5_RS_SUSPENDED:
36434ea023dSSven Schnelle         return "SUSPENDED";
36534ea023dSSven Schnelle 
36634ea023dSSven Schnelle     case CSR5_RS_RUNNING_CLOSE:
36734ea023dSSven Schnelle         return "RUNNING/CLOSE";
36834ea023dSSven Schnelle 
36934ea023dSSven Schnelle     case CSR5_RS_RUNNING_FLUSH:
37034ea023dSSven Schnelle         return "RUNNING/FLUSH";
37134ea023dSSven Schnelle 
37234ea023dSSven Schnelle     case CSR5_RS_RUNNING_QUEUE:
37334ea023dSSven Schnelle         return "RUNNING/QUEUE";
37434ea023dSSven Schnelle 
37534ea023dSSven Schnelle     default:
37634ea023dSSven Schnelle         break;
37734ea023dSSven Schnelle     }
37834ea023dSSven Schnelle     return "";
37934ea023dSSven Schnelle }
38034ea023dSSven Schnelle 
tulip_tx_state_name(int state)38134ea023dSSven Schnelle static const char *tulip_tx_state_name(int state)
38234ea023dSSven Schnelle {
38334ea023dSSven Schnelle     switch (state) {
38434ea023dSSven Schnelle     case CSR5_TS_STOPPED:
38534ea023dSSven Schnelle         return "STOPPED";
38634ea023dSSven Schnelle 
38734ea023dSSven Schnelle     case CSR5_TS_RUNNING_FETCH:
38834ea023dSSven Schnelle         return "RUNNING/FETCH";
38934ea023dSSven Schnelle 
39034ea023dSSven Schnelle     case CSR5_TS_RUNNING_WAIT_EOT:
39134ea023dSSven Schnelle         return "RUNNING/WAIT EOT";
39234ea023dSSven Schnelle 
39334ea023dSSven Schnelle     case CSR5_TS_RUNNING_READ_BUF:
39434ea023dSSven Schnelle         return "RUNNING/READ BUF";
39534ea023dSSven Schnelle 
39634ea023dSSven Schnelle     case CSR5_TS_RUNNING_SETUP:
39734ea023dSSven Schnelle         return "RUNNING/SETUP";
39834ea023dSSven Schnelle 
39934ea023dSSven Schnelle     case CSR5_TS_SUSPENDED:
40034ea023dSSven Schnelle         return "SUSPENDED";
40134ea023dSSven Schnelle 
40234ea023dSSven Schnelle     case CSR5_TS_RUNNING_CLOSE:
40334ea023dSSven Schnelle         return "RUNNING/CLOSE";
40434ea023dSSven Schnelle 
40534ea023dSSven Schnelle     default:
40634ea023dSSven Schnelle         break;
40734ea023dSSven Schnelle     }
40834ea023dSSven Schnelle     return "";
40934ea023dSSven Schnelle }
41034ea023dSSven Schnelle 
tulip_update_rs(TULIPState * s,int state)41134ea023dSSven Schnelle static void tulip_update_rs(TULIPState *s, int state)
41234ea023dSSven Schnelle {
41334ea023dSSven Schnelle     s->csr[5] &= ~(CSR5_RS_MASK << CSR5_RS_SHIFT);
41434ea023dSSven Schnelle     s->csr[5] |= (state & CSR5_RS_MASK) << CSR5_RS_SHIFT;
41534ea023dSSven Schnelle     trace_tulip_rx_state(tulip_rx_state_name(state));
41634ea023dSSven Schnelle }
41734ea023dSSven Schnelle 
41834ea023dSSven Schnelle static uint16_t tulip_mdi_default[] = {
41934ea023dSSven Schnelle     /* MDI Registers 0 - 6, 7 */
42034ea023dSSven Schnelle     0x3100, 0xf02c, 0x7810, 0x0000, 0x0501, 0x4181, 0x0000, 0x0000,
42134ea023dSSven Schnelle     /* MDI Registers 8 - 15 */
42234ea023dSSven Schnelle     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
42334ea023dSSven Schnelle     /* MDI Registers 16 - 31 */
4249b60a3edSSven Schnelle     0x0003, 0x0000, 0x0001, 0x0000, 0x3b40, 0x0000, 0x0000, 0x0000,
42534ea023dSSven Schnelle     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
42634ea023dSSven Schnelle };
42734ea023dSSven Schnelle 
42834ea023dSSven Schnelle /* Readonly mask for MDI (PHY) registers */
42934ea023dSSven Schnelle static const uint16_t tulip_mdi_mask[] = {
43034ea023dSSven Schnelle     0x0000, 0xffff, 0xffff, 0xffff, 0xc01f, 0xffff, 0xffff, 0x0000,
43134ea023dSSven Schnelle     0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
4329b60a3edSSven Schnelle     0x0fff, 0x0000, 0xffff, 0xffff, 0x0000, 0xffff, 0xffff, 0xffff,
43334ea023dSSven Schnelle     0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
43434ea023dSSven Schnelle };
43534ea023dSSven Schnelle 
tulip_mii_read(TULIPState * s,int phy,int reg)43634ea023dSSven Schnelle static uint16_t tulip_mii_read(TULIPState *s, int phy, int reg)
43734ea023dSSven Schnelle {
43834ea023dSSven Schnelle     uint16_t ret = 0;
43934ea023dSSven Schnelle     if (phy == 1) {
44034ea023dSSven Schnelle         ret = tulip_mdi_default[reg];
44134ea023dSSven Schnelle     }
44234ea023dSSven Schnelle     trace_tulip_mii_read(phy, reg, ret);
44334ea023dSSven Schnelle     return ret;
44434ea023dSSven Schnelle }
44534ea023dSSven Schnelle 
tulip_mii_write(TULIPState * s,int phy,int reg,uint16_t data)44634ea023dSSven Schnelle static void tulip_mii_write(TULIPState *s, int phy, int reg, uint16_t data)
44734ea023dSSven Schnelle {
44834ea023dSSven Schnelle     trace_tulip_mii_write(phy, reg, data);
44934ea023dSSven Schnelle 
45034ea023dSSven Schnelle     if (phy != 1) {
45134ea023dSSven Schnelle         return;
45234ea023dSSven Schnelle     }
45334ea023dSSven Schnelle 
45434ea023dSSven Schnelle     tulip_mdi_default[reg] &= ~tulip_mdi_mask[reg];
45534ea023dSSven Schnelle     tulip_mdi_default[reg] |= (data & tulip_mdi_mask[reg]);
45634ea023dSSven Schnelle }
45734ea023dSSven Schnelle 
tulip_mii(TULIPState * s)45834ea023dSSven Schnelle static void tulip_mii(TULIPState *s)
45934ea023dSSven Schnelle {
46034ea023dSSven Schnelle     uint32_t changed = s->old_csr9 ^ s->csr[9];
46134ea023dSSven Schnelle     uint16_t data;
46234ea023dSSven Schnelle     int op, phy, reg;
46334ea023dSSven Schnelle 
46434ea023dSSven Schnelle     if (!(changed & CSR9_MDC)) {
46534ea023dSSven Schnelle         return;
46634ea023dSSven Schnelle     }
46734ea023dSSven Schnelle 
46834ea023dSSven Schnelle     if (!(s->csr[9] & CSR9_MDC)) {
46934ea023dSSven Schnelle         return;
47034ea023dSSven Schnelle     }
47134ea023dSSven Schnelle 
47234ea023dSSven Schnelle     s->mii_bitcnt++;
47334ea023dSSven Schnelle     s->mii_word <<= 1;
47434ea023dSSven Schnelle 
47534ea023dSSven Schnelle     if (s->csr[9] & CSR9_MDO && (s->mii_bitcnt < 16 ||
47634ea023dSSven Schnelle         !(s->csr[9] & CSR9_MII))) {
47734ea023dSSven Schnelle         /* write op or address bits */
47834ea023dSSven Schnelle         s->mii_word |= 1;
47934ea023dSSven Schnelle     }
48034ea023dSSven Schnelle 
48134ea023dSSven Schnelle     if (s->mii_bitcnt >= 16 && (s->csr[9] & CSR9_MII)) {
48234ea023dSSven Schnelle         if (s->mii_word & 0x8000) {
48334ea023dSSven Schnelle             s->csr[9] |= CSR9_MDI;
48434ea023dSSven Schnelle         } else {
48534ea023dSSven Schnelle             s->csr[9] &= ~CSR9_MDI;
48634ea023dSSven Schnelle         }
48734ea023dSSven Schnelle     }
48834ea023dSSven Schnelle 
48934ea023dSSven Schnelle     if (s->mii_word == 0xffffffff) {
49034ea023dSSven Schnelle         s->mii_bitcnt = 0;
49134ea023dSSven Schnelle     } else if (s->mii_bitcnt == 16) {
49234ea023dSSven Schnelle         op = (s->mii_word >> 12) & 0x0f;
49334ea023dSSven Schnelle         phy = (s->mii_word >> 7) & 0x1f;
49434ea023dSSven Schnelle         reg = (s->mii_word >> 2) & 0x1f;
49534ea023dSSven Schnelle 
49634ea023dSSven Schnelle         if (op == 6) {
49734ea023dSSven Schnelle             s->mii_word = tulip_mii_read(s, phy, reg);
49834ea023dSSven Schnelle         }
49934ea023dSSven Schnelle     } else if (s->mii_bitcnt == 32) {
50034ea023dSSven Schnelle             op = (s->mii_word >> 28) & 0x0f;
50134ea023dSSven Schnelle             phy = (s->mii_word >> 23) & 0x1f;
50234ea023dSSven Schnelle             reg = (s->mii_word >> 18) & 0x1f;
50334ea023dSSven Schnelle             data = s->mii_word & 0xffff;
50434ea023dSSven Schnelle 
50534ea023dSSven Schnelle         if (op == 5) {
50634ea023dSSven Schnelle             tulip_mii_write(s, phy, reg, data);
50734ea023dSSven Schnelle         }
50834ea023dSSven Schnelle     }
50934ea023dSSven Schnelle }
51034ea023dSSven Schnelle 
tulip_csr9_read(TULIPState * s)51134ea023dSSven Schnelle static uint32_t tulip_csr9_read(TULIPState *s)
51234ea023dSSven Schnelle {
51334ea023dSSven Schnelle     if (s->csr[9] & CSR9_SR) {
51434ea023dSSven Schnelle         if (eeprom93xx_read(s->eeprom)) {
51534ea023dSSven Schnelle             s->csr[9] |= CSR9_SR_DO;
51634ea023dSSven Schnelle         } else {
51734ea023dSSven Schnelle             s->csr[9] &= ~CSR9_SR_DO;
51834ea023dSSven Schnelle         }
51934ea023dSSven Schnelle     }
52034ea023dSSven Schnelle 
52134ea023dSSven Schnelle     tulip_mii(s);
52234ea023dSSven Schnelle     return s->csr[9];
52334ea023dSSven Schnelle }
52434ea023dSSven Schnelle 
tulip_update_ts(TULIPState * s,int state)52534ea023dSSven Schnelle static void tulip_update_ts(TULIPState *s, int state)
52634ea023dSSven Schnelle {
52734ea023dSSven Schnelle         s->csr[5] &= ~(CSR5_TS_MASK << CSR5_TS_SHIFT);
52834ea023dSSven Schnelle         s->csr[5] |= (state & CSR5_TS_MASK) << CSR5_TS_SHIFT;
52934ea023dSSven Schnelle         trace_tulip_tx_state(tulip_tx_state_name(state));
53034ea023dSSven Schnelle }
53134ea023dSSven Schnelle 
tulip_read(void * opaque,hwaddr addr,unsigned size)53234ea023dSSven Schnelle static uint64_t tulip_read(void *opaque, hwaddr addr,
53334ea023dSSven Schnelle                               unsigned size)
53434ea023dSSven Schnelle {
53534ea023dSSven Schnelle     TULIPState *s = opaque;
53634ea023dSSven Schnelle     uint64_t data = 0;
53734ea023dSSven Schnelle 
53834ea023dSSven Schnelle     switch (addr) {
53934ea023dSSven Schnelle     case CSR(9):
54034ea023dSSven Schnelle         data = tulip_csr9_read(s);
54134ea023dSSven Schnelle         break;
54234ea023dSSven Schnelle 
54334ea023dSSven Schnelle     case CSR(12):
54434ea023dSSven Schnelle         /* Fake autocompletion complete until we have PHY emulation */
54534ea023dSSven Schnelle         data = 5 << CSR12_ANS_SHIFT;
54634ea023dSSven Schnelle         break;
54734ea023dSSven Schnelle 
54834ea023dSSven Schnelle     default:
54934ea023dSSven Schnelle         if (addr & 7) {
55034ea023dSSven Schnelle             qemu_log_mask(LOG_GUEST_ERROR, "%s: read access at unknown address"
55134ea023dSSven Schnelle                 " 0x%"PRIx64"\n", __func__, addr);
55234ea023dSSven Schnelle         } else {
55334ea023dSSven Schnelle             data = s->csr[addr >> 3];
55434ea023dSSven Schnelle         }
55534ea023dSSven Schnelle         break;
55634ea023dSSven Schnelle     }
55734ea023dSSven Schnelle     trace_tulip_reg_read(addr, tulip_reg_name(addr), size, data);
55834ea023dSSven Schnelle     return data;
55934ea023dSSven Schnelle }
56034ea023dSSven Schnelle 
tulip_tx(TULIPState * s,struct tulip_descriptor * desc)56134ea023dSSven Schnelle static void tulip_tx(TULIPState *s, struct tulip_descriptor *desc)
56234ea023dSSven Schnelle {
56334ea023dSSven Schnelle     if (s->tx_frame_len) {
56434ea023dSSven Schnelle         if ((s->csr[6] >> CSR6_OM_SHIFT) & CSR6_OM_MASK) {
56534ea023dSSven Schnelle             /* Internal or external Loopback */
56634ea023dSSven Schnelle             tulip_receive(s, s->tx_frame, s->tx_frame_len);
5678ffb7265SPrasad J Pandit         } else if (s->tx_frame_len <= sizeof(s->tx_frame)) {
56834ea023dSSven Schnelle             qemu_send_packet(qemu_get_queue(s->nic),
56934ea023dSSven Schnelle                 s->tx_frame, s->tx_frame_len);
57034ea023dSSven Schnelle         }
57134ea023dSSven Schnelle     }
57234ea023dSSven Schnelle 
57334ea023dSSven Schnelle     if (desc->control & TDES1_IC) {
57434ea023dSSven Schnelle         s->csr[5] |= CSR5_TI;
57534ea023dSSven Schnelle         tulip_update_int(s);
57634ea023dSSven Schnelle     }
57734ea023dSSven Schnelle }
57834ea023dSSven Schnelle 
tulip_copy_tx_buffers(TULIPState * s,struct tulip_descriptor * desc)5798ffb7265SPrasad J Pandit static int tulip_copy_tx_buffers(TULIPState *s, struct tulip_descriptor *desc)
58034ea023dSSven Schnelle {
58134ea023dSSven Schnelle     int len1 = (desc->control >> TDES1_BUF1_SIZE_SHIFT) & TDES1_BUF1_SIZE_MASK;
58234ea023dSSven Schnelle     int len2 = (desc->control >> TDES1_BUF2_SIZE_SHIFT) & TDES1_BUF2_SIZE_MASK;
58334ea023dSSven Schnelle 
5848ffb7265SPrasad J Pandit     if (s->tx_frame_len + len1 > sizeof(s->tx_frame)) {
58597d7fb5aSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR,
58697d7fb5aSPhilippe Mathieu-Daudé                       "%s: descriptor overflow (ofs: %u, len:%d, size:%zu)\n",
58797d7fb5aSPhilippe Mathieu-Daudé                       __func__, s->tx_frame_len, len1, sizeof(s->tx_frame));
5888ffb7265SPrasad J Pandit         return -1;
5898ffb7265SPrasad J Pandit     }
59034ea023dSSven Schnelle     if (len1) {
59134ea023dSSven Schnelle         pci_dma_read(&s->dev, desc->buf_addr1,
59234ea023dSSven Schnelle             s->tx_frame + s->tx_frame_len, len1);
59334ea023dSSven Schnelle         s->tx_frame_len += len1;
59434ea023dSSven Schnelle     }
59534ea023dSSven Schnelle 
5968ffb7265SPrasad J Pandit     if (s->tx_frame_len + len2 > sizeof(s->tx_frame)) {
59797d7fb5aSPhilippe Mathieu-Daudé         qemu_log_mask(LOG_GUEST_ERROR,
59897d7fb5aSPhilippe Mathieu-Daudé                       "%s: descriptor overflow (ofs: %u, len:%d, size:%zu)\n",
59997d7fb5aSPhilippe Mathieu-Daudé                       __func__, s->tx_frame_len, len2, sizeof(s->tx_frame));
6008ffb7265SPrasad J Pandit         return -1;
6018ffb7265SPrasad J Pandit     }
60234ea023dSSven Schnelle     if (len2) {
60334ea023dSSven Schnelle         pci_dma_read(&s->dev, desc->buf_addr2,
60434ea023dSSven Schnelle             s->tx_frame + s->tx_frame_len, len2);
60534ea023dSSven Schnelle         s->tx_frame_len += len2;
60634ea023dSSven Schnelle     }
60734ea023dSSven Schnelle     desc->status = (len1 + len2) ? 0 : 0x7fffffff;
6088ffb7265SPrasad J Pandit 
6098ffb7265SPrasad J Pandit     return 0;
61034ea023dSSven Schnelle }
61134ea023dSSven Schnelle 
tulip_setup_filter_addr(TULIPState * s,uint8_t * buf,int n)61234ea023dSSven Schnelle static void tulip_setup_filter_addr(TULIPState *s, uint8_t *buf, int n)
61334ea023dSSven Schnelle {
61434ea023dSSven Schnelle     int offset = n * 12;
61534ea023dSSven Schnelle 
61634ea023dSSven Schnelle     s->filter[n][0] = buf[offset];
61734ea023dSSven Schnelle     s->filter[n][1] = buf[offset + 1];
61834ea023dSSven Schnelle 
61934ea023dSSven Schnelle     s->filter[n][2] = buf[offset + 4];
62034ea023dSSven Schnelle     s->filter[n][3] = buf[offset + 5];
62134ea023dSSven Schnelle 
62234ea023dSSven Schnelle     s->filter[n][4] = buf[offset + 8];
62334ea023dSSven Schnelle     s->filter[n][5] = buf[offset + 9];
62434ea023dSSven Schnelle 
62534ea023dSSven Schnelle     trace_tulip_setup_filter(n, s->filter[n][5], s->filter[n][4],
62634ea023dSSven Schnelle             s->filter[n][3], s->filter[n][2], s->filter[n][1], s->filter[n][0]);
62734ea023dSSven Schnelle }
62834ea023dSSven Schnelle 
tulip_setup_frame(TULIPState * s,struct tulip_descriptor * desc)62934ea023dSSven Schnelle static void tulip_setup_frame(TULIPState *s,
63034ea023dSSven Schnelle         struct tulip_descriptor *desc)
63134ea023dSSven Schnelle {
63234ea023dSSven Schnelle     uint8_t buf[4096];
63334ea023dSSven Schnelle     int len = (desc->control >> TDES1_BUF1_SIZE_SHIFT) & TDES1_BUF1_SIZE_MASK;
63434ea023dSSven Schnelle     int i;
63534ea023dSSven Schnelle 
63634ea023dSSven Schnelle     trace_tulip_setup_frame();
63734ea023dSSven Schnelle 
63834ea023dSSven Schnelle     if (len == 192) {
63934ea023dSSven Schnelle         pci_dma_read(&s->dev, desc->buf_addr1, buf, len);
64034ea023dSSven Schnelle         for (i = 0; i < 16; i++) {
64134ea023dSSven Schnelle             tulip_setup_filter_addr(s, buf, i);
64234ea023dSSven Schnelle         }
64334ea023dSSven Schnelle     }
64434ea023dSSven Schnelle 
64534ea023dSSven Schnelle     desc->status = 0x7fffffff;
64634ea023dSSven Schnelle 
64734ea023dSSven Schnelle     if (desc->control & TDES1_IC) {
64834ea023dSSven Schnelle         s->csr[5] |= CSR5_TI;
64934ea023dSSven Schnelle         tulip_update_int(s);
65034ea023dSSven Schnelle     }
65134ea023dSSven Schnelle }
65234ea023dSSven Schnelle 
tulip_next_tx_descriptor(TULIPState * s,struct tulip_descriptor * desc)65334ea023dSSven Schnelle static void tulip_next_tx_descriptor(TULIPState *s,
65434ea023dSSven Schnelle     struct tulip_descriptor *desc)
65534ea023dSSven Schnelle {
65634ea023dSSven Schnelle     if (desc->control & TDES1_TER) {
65734ea023dSSven Schnelle         s->current_tx_desc = s->csr[4];
65834ea023dSSven Schnelle     } else if (desc->control & TDES1_TCH) {
65934ea023dSSven Schnelle         s->current_tx_desc = desc->buf_addr2;
66034ea023dSSven Schnelle     } else {
66134ea023dSSven Schnelle         s->current_tx_desc += sizeof(struct tulip_descriptor) +
66234ea023dSSven Schnelle                 (((s->csr[0] >> CSR0_DSL_SHIFT) & CSR0_DSL_MASK) << 2);
66334ea023dSSven Schnelle     }
66434ea023dSSven Schnelle     s->current_tx_desc &= ~3ULL;
66534ea023dSSven Schnelle }
66634ea023dSSven Schnelle 
tulip_ts(TULIPState * s)66734ea023dSSven Schnelle static uint32_t tulip_ts(TULIPState *s)
66834ea023dSSven Schnelle {
66934ea023dSSven Schnelle     return (s->csr[5] >> CSR5_TS_SHIFT) & CSR5_TS_MASK;
67034ea023dSSven Schnelle }
67134ea023dSSven Schnelle 
tulip_xmit_list_update(TULIPState * s)67234ea023dSSven Schnelle static void tulip_xmit_list_update(TULIPState *s)
67334ea023dSSven Schnelle {
6748ffb7265SPrasad J Pandit #define TULIP_DESC_MAX 128
6758ffb7265SPrasad J Pandit     uint8_t i = 0;
67634ea023dSSven Schnelle     struct tulip_descriptor desc;
67734ea023dSSven Schnelle 
67834ea023dSSven Schnelle     if (tulip_ts(s) != CSR5_TS_SUSPENDED) {
67934ea023dSSven Schnelle         return;
68034ea023dSSven Schnelle     }
68134ea023dSSven Schnelle 
6828ffb7265SPrasad J Pandit     for (i = 0; i < TULIP_DESC_MAX; i++) {
68334ea023dSSven Schnelle         tulip_desc_read(s, s->current_tx_desc, &desc);
68434ea023dSSven Schnelle         tulip_dump_tx_descriptor(s, &desc);
68534ea023dSSven Schnelle 
68634ea023dSSven Schnelle         if (!(desc.status & TDES0_OWN)) {
68734ea023dSSven Schnelle             tulip_update_ts(s, CSR5_TS_SUSPENDED);
68834ea023dSSven Schnelle             s->csr[5] |= CSR5_TU;
68934ea023dSSven Schnelle             tulip_update_int(s);
69034ea023dSSven Schnelle             return;
69134ea023dSSven Schnelle         }
69234ea023dSSven Schnelle 
69334ea023dSSven Schnelle         if (desc.control & TDES1_SET) {
69434ea023dSSven Schnelle             tulip_setup_frame(s, &desc);
69534ea023dSSven Schnelle         } else {
69634ea023dSSven Schnelle             if (desc.control & TDES1_FS) {
69734ea023dSSven Schnelle                 s->tx_frame_len = 0;
69834ea023dSSven Schnelle             }
69934ea023dSSven Schnelle 
7008ffb7265SPrasad J Pandit             if (!tulip_copy_tx_buffers(s, &desc)) {
70134ea023dSSven Schnelle                 if (desc.control & TDES1_LS) {
70234ea023dSSven Schnelle                     tulip_tx(s, &desc);
70334ea023dSSven Schnelle                 }
70434ea023dSSven Schnelle             }
7058ffb7265SPrasad J Pandit         }
70634ea023dSSven Schnelle         tulip_desc_write(s, s->current_tx_desc, &desc);
70734ea023dSSven Schnelle         tulip_next_tx_descriptor(s, &desc);
70834ea023dSSven Schnelle     }
70934ea023dSSven Schnelle }
71034ea023dSSven Schnelle 
tulip_csr9_write(TULIPState * s,uint32_t old_val,uint32_t new_val)71134ea023dSSven Schnelle static void tulip_csr9_write(TULIPState *s, uint32_t old_val,
71234ea023dSSven Schnelle         uint32_t new_val)
71334ea023dSSven Schnelle {
71434ea023dSSven Schnelle     if (new_val & CSR9_SR) {
71534ea023dSSven Schnelle         eeprom93xx_write(s->eeprom,
71634ea023dSSven Schnelle             !!(new_val & CSR9_SR_CS),
71734ea023dSSven Schnelle             !!(new_val & CSR9_SR_SK),
71834ea023dSSven Schnelle             !!(new_val & CSR9_SR_DI));
71934ea023dSSven Schnelle     }
72034ea023dSSven Schnelle }
72134ea023dSSven Schnelle 
tulip_reset(TULIPState * s)72234ea023dSSven Schnelle static void tulip_reset(TULIPState *s)
72334ea023dSSven Schnelle {
72434ea023dSSven Schnelle     trace_tulip_reset();
72534ea023dSSven Schnelle 
72634ea023dSSven Schnelle     s->csr[0] = 0xfe000000;
72734ea023dSSven Schnelle     s->csr[1] = 0xffffffff;
72834ea023dSSven Schnelle     s->csr[2] = 0xffffffff;
72934ea023dSSven Schnelle     s->csr[5] = 0xf0000000;
73034ea023dSSven Schnelle     s->csr[6] = 0x32000040;
73134ea023dSSven Schnelle     s->csr[7] = 0xf3fe0000;
73234ea023dSSven Schnelle     s->csr[8] = 0xe0000000;
73334ea023dSSven Schnelle     s->csr[9] = 0xfff483ff;
73434ea023dSSven Schnelle     s->csr[11] = 0xfffe0000;
73534ea023dSSven Schnelle     s->csr[12] = 0x000000c6;
73634ea023dSSven Schnelle     s->csr[13] = 0xffff0000;
73734ea023dSSven Schnelle     s->csr[14] = 0xffffffff;
73834ea023dSSven Schnelle     s->csr[15] = 0x8ff00000;
73934ea023dSSven Schnelle }
74034ea023dSSven Schnelle 
tulip_qdev_reset(DeviceState * dev)74134ea023dSSven Schnelle static void tulip_qdev_reset(DeviceState *dev)
74234ea023dSSven Schnelle {
74334ea023dSSven Schnelle     PCIDevice *d = PCI_DEVICE(dev);
74434ea023dSSven Schnelle     TULIPState *s = TULIP(d);
74534ea023dSSven Schnelle 
74634ea023dSSven Schnelle     tulip_reset(s);
74734ea023dSSven Schnelle }
74834ea023dSSven Schnelle 
tulip_write(void * opaque,hwaddr addr,uint64_t data,unsigned size)74934ea023dSSven Schnelle static void tulip_write(void *opaque, hwaddr addr,
75034ea023dSSven Schnelle                            uint64_t data, unsigned size)
75134ea023dSSven Schnelle {
75234ea023dSSven Schnelle     TULIPState *s = opaque;
75334ea023dSSven Schnelle     trace_tulip_reg_write(addr, tulip_reg_name(addr), size, data);
75434ea023dSSven Schnelle 
75534ea023dSSven Schnelle     switch (addr) {
75634ea023dSSven Schnelle     case CSR(0):
75734ea023dSSven Schnelle         s->csr[0] = data;
75834ea023dSSven Schnelle         if (data & CSR0_SWR) {
75934ea023dSSven Schnelle             tulip_reset(s);
76034ea023dSSven Schnelle             tulip_update_int(s);
76134ea023dSSven Schnelle         }
76234ea023dSSven Schnelle         break;
76334ea023dSSven Schnelle 
76434ea023dSSven Schnelle     case CSR(1):
76534ea023dSSven Schnelle         tulip_xmit_list_update(s);
76634ea023dSSven Schnelle         break;
76734ea023dSSven Schnelle 
76834ea023dSSven Schnelle     case CSR(2):
76934ea023dSSven Schnelle         qemu_flush_queued_packets(qemu_get_queue(s->nic));
77034ea023dSSven Schnelle         break;
77134ea023dSSven Schnelle 
77234ea023dSSven Schnelle     case CSR(3):
77334ea023dSSven Schnelle         s->csr[3] = data & ~3ULL;
77434ea023dSSven Schnelle         s->current_rx_desc = s->csr[3];
77534ea023dSSven Schnelle         qemu_flush_queued_packets(qemu_get_queue(s->nic));
77634ea023dSSven Schnelle         break;
77734ea023dSSven Schnelle 
77834ea023dSSven Schnelle     case CSR(4):
77934ea023dSSven Schnelle         s->csr[4] = data & ~3ULL;
78034ea023dSSven Schnelle         s->current_tx_desc = s->csr[4];
78134ea023dSSven Schnelle         tulip_xmit_list_update(s);
78234ea023dSSven Schnelle         break;
78334ea023dSSven Schnelle 
78434ea023dSSven Schnelle     case CSR(5):
78534ea023dSSven Schnelle         /* Status register, write clears bit */
78634ea023dSSven Schnelle         s->csr[5] &= ~(data & (CSR5_TI | CSR5_TPS | CSR5_TU | CSR5_TJT |
78734ea023dSSven Schnelle                                CSR5_LNP_ANC | CSR5_UNF | CSR5_RI | CSR5_RU |
78834ea023dSSven Schnelle                                CSR5_RPS | CSR5_RWT | CSR5_ETI | CSR5_GTE |
78934ea023dSSven Schnelle                                CSR5_LNF | CSR5_FBE | CSR5_ERI | CSR5_AIS |
79034ea023dSSven Schnelle                                CSR5_NIS | CSR5_GPI | CSR5_LC));
79134ea023dSSven Schnelle         tulip_update_int(s);
79234ea023dSSven Schnelle         break;
79334ea023dSSven Schnelle 
79434ea023dSSven Schnelle     case CSR(6):
79534ea023dSSven Schnelle         s->csr[6] = data;
79634ea023dSSven Schnelle         if (s->csr[6] & CSR6_SR) {
79734ea023dSSven Schnelle             tulip_update_rs(s, CSR5_RS_RUNNING_WAIT_RECEIVE);
79834ea023dSSven Schnelle             qemu_flush_queued_packets(qemu_get_queue(s->nic));
79934ea023dSSven Schnelle         } else {
80034ea023dSSven Schnelle             tulip_update_rs(s, CSR5_RS_STOPPED);
80134ea023dSSven Schnelle         }
80234ea023dSSven Schnelle 
80334ea023dSSven Schnelle         if (s->csr[6] & CSR6_ST) {
80434ea023dSSven Schnelle             tulip_update_ts(s, CSR5_TS_SUSPENDED);
80534ea023dSSven Schnelle             tulip_xmit_list_update(s);
80634ea023dSSven Schnelle         } else {
80734ea023dSSven Schnelle             tulip_update_ts(s, CSR5_TS_STOPPED);
80834ea023dSSven Schnelle         }
80934ea023dSSven Schnelle         break;
81034ea023dSSven Schnelle 
81134ea023dSSven Schnelle     case CSR(7):
81234ea023dSSven Schnelle         s->csr[7] = data;
81334ea023dSSven Schnelle         tulip_update_int(s);
81434ea023dSSven Schnelle         break;
81534ea023dSSven Schnelle 
81634ea023dSSven Schnelle     case CSR(8):
81734ea023dSSven Schnelle         s->csr[9] = data;
81834ea023dSSven Schnelle         break;
81934ea023dSSven Schnelle 
82034ea023dSSven Schnelle     case CSR(9):
82134ea023dSSven Schnelle         tulip_csr9_write(s, s->csr[9], data);
82234ea023dSSven Schnelle         /* don't clear MII read data */
82334ea023dSSven Schnelle         s->csr[9] &= CSR9_MDI;
82434ea023dSSven Schnelle         s->csr[9] |= (data & ~CSR9_MDI);
82534ea023dSSven Schnelle         tulip_mii(s);
82634ea023dSSven Schnelle         s->old_csr9 = s->csr[9];
82734ea023dSSven Schnelle         break;
82834ea023dSSven Schnelle 
82934ea023dSSven Schnelle     case CSR(10):
83034ea023dSSven Schnelle         s->csr[10] = data;
83134ea023dSSven Schnelle         break;
83234ea023dSSven Schnelle 
83334ea023dSSven Schnelle     case CSR(11):
83434ea023dSSven Schnelle         s->csr[11] = data;
83534ea023dSSven Schnelle         break;
83634ea023dSSven Schnelle 
83734ea023dSSven Schnelle     case CSR(12):
83834ea023dSSven Schnelle         /* SIA Status register, some bits are cleared by writing 1 */
83934ea023dSSven Schnelle         s->csr[12] &= ~(data & (CSR12_MRA | CSR12_TRA | CSR12_ARA));
84034ea023dSSven Schnelle         break;
84134ea023dSSven Schnelle 
84234ea023dSSven Schnelle     case CSR(13):
84334ea023dSSven Schnelle         s->csr[13] = data;
84434ea023dSSven Schnelle         break;
84534ea023dSSven Schnelle 
84634ea023dSSven Schnelle     case CSR(14):
84734ea023dSSven Schnelle         s->csr[14] = data;
84834ea023dSSven Schnelle         break;
84934ea023dSSven Schnelle 
85034ea023dSSven Schnelle     case CSR(15):
85134ea023dSSven Schnelle         s->csr[15] = data;
85234ea023dSSven Schnelle         break;
85334ea023dSSven Schnelle 
85434ea023dSSven Schnelle     default:
85534ea023dSSven Schnelle         qemu_log_mask(LOG_GUEST_ERROR, "%s: write to CSR at unknown address "
85634ea023dSSven Schnelle                 "0x%"PRIx64"\n", __func__, addr);
85734ea023dSSven Schnelle         break;
85834ea023dSSven Schnelle     }
85934ea023dSSven Schnelle }
86034ea023dSSven Schnelle 
86134ea023dSSven Schnelle static const MemoryRegionOps tulip_ops = {
86234ea023dSSven Schnelle     .read = tulip_read,
86334ea023dSSven Schnelle     .write = tulip_write,
86434ea023dSSven Schnelle     .endianness = DEVICE_LITTLE_ENDIAN,
86534ea023dSSven Schnelle     .impl = {
86634ea023dSSven Schnelle         .min_access_size = 4,
86734ea023dSSven Schnelle         .max_access_size = 4,
86834ea023dSSven Schnelle     },
86934ea023dSSven Schnelle };
87034ea023dSSven Schnelle 
tulip_idblock_crc(TULIPState * s,uint16_t * srom)87134ea023dSSven Schnelle static void tulip_idblock_crc(TULIPState *s, uint16_t *srom)
87234ea023dSSven Schnelle {
8736083dcadSMiroslav Rezanina     int word;
87434ea023dSSven Schnelle     int bit;
87534ea023dSSven Schnelle     unsigned char bitval, crc;
87634ea023dSSven Schnelle     const int len = 9;
87734ea023dSSven Schnelle     crc = -1;
87834ea023dSSven Schnelle 
87934ea023dSSven Schnelle     for (word = 0; word < len; word++) {
88034ea023dSSven Schnelle         for (bit = 15; bit >= 0; bit--) {
88134ea023dSSven Schnelle             if ((word == (len - 1)) && (bit == 7)) {
88234ea023dSSven Schnelle                 /*
88334ea023dSSven Schnelle                  * Insert the correct CRC result into input data stream
88434ea023dSSven Schnelle                  * in place.
88534ea023dSSven Schnelle                  */
88634ea023dSSven Schnelle                 srom[len - 1] = (srom[len - 1] & 0xff00) | (unsigned short)crc;
88734ea023dSSven Schnelle                 break;
88834ea023dSSven Schnelle             }
88934ea023dSSven Schnelle             bitval = ((srom[word] >> bit) & 1) ^ ((crc >> 7) & 1);
89034ea023dSSven Schnelle             crc = crc << 1;
89134ea023dSSven Schnelle             if (bitval == 1) {
89234ea023dSSven Schnelle                 crc ^= 6;
89334ea023dSSven Schnelle                 crc |= 0x01;
89434ea023dSSven Schnelle             }
89534ea023dSSven Schnelle         }
89634ea023dSSven Schnelle     }
89734ea023dSSven Schnelle }
89834ea023dSSven Schnelle 
tulip_srom_crc(TULIPState * s,uint8_t * eeprom,size_t len)89934ea023dSSven Schnelle static uint16_t tulip_srom_crc(TULIPState *s, uint8_t *eeprom, size_t len)
90034ea023dSSven Schnelle {
90134ea023dSSven Schnelle     unsigned long crc = 0xffffffff;
90234ea023dSSven Schnelle     unsigned long flippedcrc = 0;
90334ea023dSSven Schnelle     unsigned char currentbyte;
90434ea023dSSven Schnelle     unsigned int msb, bit, i;
90534ea023dSSven Schnelle 
90634ea023dSSven Schnelle     for (i = 0; i < len; i++) {
90734ea023dSSven Schnelle         currentbyte = eeprom[i];
90834ea023dSSven Schnelle         for (bit = 0; bit < 8; bit++) {
90934ea023dSSven Schnelle             msb = (crc >> 31) & 1;
91034ea023dSSven Schnelle             crc <<= 1;
91134ea023dSSven Schnelle             if (msb ^ (currentbyte & 1)) {
91234ea023dSSven Schnelle                 crc ^= 0x04c11db6;
91334ea023dSSven Schnelle                 crc |= 0x00000001;
91434ea023dSSven Schnelle             }
91534ea023dSSven Schnelle             currentbyte >>= 1;
91634ea023dSSven Schnelle         }
91734ea023dSSven Schnelle     }
91834ea023dSSven Schnelle 
91934ea023dSSven Schnelle     for (i = 0; i < 32; i++) {
92034ea023dSSven Schnelle         flippedcrc <<= 1;
92134ea023dSSven Schnelle         bit = crc & 1;
92234ea023dSSven Schnelle         crc >>= 1;
92334ea023dSSven Schnelle         flippedcrc += bit;
92434ea023dSSven Schnelle     }
92534ea023dSSven Schnelle     return (flippedcrc ^ 0xffffffff) & 0xffff;
92634ea023dSSven Schnelle }
92734ea023dSSven Schnelle 
92834ea023dSSven Schnelle static const uint8_t eeprom_default[128] = {
92934ea023dSSven Schnelle     0x3c, 0x10, 0x4f, 0x10, 0x00, 0x00, 0x00, 0x00,
93034ea023dSSven Schnelle     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
93134ea023dSSven Schnelle     0x56, 0x08, 0x04, 0x01, 0x00, 0x80, 0x48, 0xb3,
93234ea023dSSven Schnelle     0x0e, 0xa7, 0x00, 0x1e, 0x00, 0x00, 0x00, 0x08,
93334ea023dSSven Schnelle     0x01, 0x8d, 0x03, 0x00, 0x00, 0x00, 0x00, 0x78,
93434ea023dSSven Schnelle     0xe0, 0x01, 0x00, 0x50, 0x00, 0x18, 0x00, 0x00,
93534ea023dSSven Schnelle     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
93634ea023dSSven Schnelle     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
93734ea023dSSven Schnelle     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
93834ea023dSSven Schnelle     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
93934ea023dSSven Schnelle     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
94034ea023dSSven Schnelle     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x6b,
94134ea023dSSven Schnelle     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
94234ea023dSSven Schnelle     0x48, 0xb3, 0x0e, 0xa7, 0x40, 0x00, 0x00, 0x00,
94334ea023dSSven Schnelle     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
94434ea023dSSven Schnelle     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
94534ea023dSSven Schnelle };
94634ea023dSSven Schnelle 
tulip_fill_eeprom(TULIPState * s)94734ea023dSSven Schnelle static void tulip_fill_eeprom(TULIPState *s)
94834ea023dSSven Schnelle {
94934ea023dSSven Schnelle     uint16_t *eeprom = eeprom93xx_data(s->eeprom);
95034ea023dSSven Schnelle     memcpy(eeprom, eeprom_default, 128);
95134ea023dSSven Schnelle 
95234ea023dSSven Schnelle     /* patch in our mac address */
95334ea023dSSven Schnelle     eeprom[10] = cpu_to_le16(s->c.macaddr.a[0] | (s->c.macaddr.a[1] << 8));
95434ea023dSSven Schnelle     eeprom[11] = cpu_to_le16(s->c.macaddr.a[2] | (s->c.macaddr.a[3] << 8));
95534ea023dSSven Schnelle     eeprom[12] = cpu_to_le16(s->c.macaddr.a[4] | (s->c.macaddr.a[5] << 8));
95634ea023dSSven Schnelle     tulip_idblock_crc(s, eeprom);
95734ea023dSSven Schnelle     eeprom[63] = cpu_to_le16(tulip_srom_crc(s, (uint8_t *)eeprom, 126));
95834ea023dSSven Schnelle }
95934ea023dSSven Schnelle 
pci_tulip_realize(PCIDevice * pci_dev,Error ** errp)96034ea023dSSven Schnelle static void pci_tulip_realize(PCIDevice *pci_dev, Error **errp)
96134ea023dSSven Schnelle {
96234ea023dSSven Schnelle     TULIPState *s = DO_UPCAST(TULIPState, dev, pci_dev);
96334ea023dSSven Schnelle     uint8_t *pci_conf;
96434ea023dSSven Schnelle 
96534ea023dSSven Schnelle     pci_conf = s->dev.config;
96634ea023dSSven Schnelle     pci_conf[PCI_INTERRUPT_PIN] = 1; /* interrupt pin A */
96734ea023dSSven Schnelle 
968052c2579SHelge Deller     qemu_macaddr_default_if_unset(&s->c.macaddr);
969052c2579SHelge Deller 
97034ea023dSSven Schnelle     s->eeprom = eeprom93xx_new(&pci_dev->qdev, 64);
97134ea023dSSven Schnelle     tulip_fill_eeprom(s);
97234ea023dSSven Schnelle 
97334ea023dSSven Schnelle     memory_region_init_io(&s->io, OBJECT(&s->dev), &tulip_ops, s,
97434ea023dSSven Schnelle             "tulip-io", 128);
97534ea023dSSven Schnelle 
97634ea023dSSven Schnelle     memory_region_init_io(&s->memory, OBJECT(&s->dev), &tulip_ops, s,
97734ea023dSSven Schnelle             "tulip-mem", 128);
97834ea023dSSven Schnelle 
97934ea023dSSven Schnelle     pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &s->io);
98034ea023dSSven Schnelle     pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->memory);
98134ea023dSSven Schnelle 
98234ea023dSSven Schnelle     s->irq = pci_allocate_irq(&s->dev);
98334ea023dSSven Schnelle 
98434ea023dSSven Schnelle     s->nic = qemu_new_nic(&net_tulip_info, &s->c,
98534ea023dSSven Schnelle                           object_get_typename(OBJECT(pci_dev)),
9867d0fefdfSAkihiko Odaki                           pci_dev->qdev.id,
9877d0fefdfSAkihiko Odaki                           &pci_dev->qdev.mem_reentrancy_guard, s);
98834ea023dSSven Schnelle     qemu_format_nic_info_str(qemu_get_queue(s->nic), s->c.macaddr.a);
98934ea023dSSven Schnelle }
99034ea023dSSven Schnelle 
pci_tulip_exit(PCIDevice * pci_dev)99134ea023dSSven Schnelle static void pci_tulip_exit(PCIDevice *pci_dev)
99234ea023dSSven Schnelle {
99334ea023dSSven Schnelle     TULIPState *s = DO_UPCAST(TULIPState, dev, pci_dev);
99434ea023dSSven Schnelle 
99534ea023dSSven Schnelle     qemu_del_nic(s->nic);
99634ea023dSSven Schnelle     qemu_free_irq(s->irq);
99734ea023dSSven Schnelle     eeprom93xx_free(&pci_dev->qdev, s->eeprom);
99834ea023dSSven Schnelle }
99934ea023dSSven Schnelle 
tulip_instance_init(Object * obj)100034ea023dSSven Schnelle static void tulip_instance_init(Object *obj)
100134ea023dSSven Schnelle {
100234ea023dSSven Schnelle     PCIDevice *pci_dev = PCI_DEVICE(obj);
100334ea023dSSven Schnelle     TULIPState *d = DO_UPCAST(TULIPState, dev, pci_dev);
100434ea023dSSven Schnelle 
100534ea023dSSven Schnelle     device_add_bootindex_property(obj, &d->c.bootindex,
100634ea023dSSven Schnelle                                   "bootindex", "/ethernet-phy@0",
100740c2281cSMarkus Armbruster                                   &pci_dev->qdev);
100834ea023dSSven Schnelle }
100934ea023dSSven Schnelle 
101034ea023dSSven Schnelle static Property tulip_properties[] = {
101134ea023dSSven Schnelle     DEFINE_NIC_PROPERTIES(TULIPState, c),
101234ea023dSSven Schnelle     DEFINE_PROP_END_OF_LIST(),
101334ea023dSSven Schnelle };
101434ea023dSSven Schnelle 
tulip_class_init(ObjectClass * klass,void * data)101534ea023dSSven Schnelle static void tulip_class_init(ObjectClass *klass, void *data)
101634ea023dSSven Schnelle {
101734ea023dSSven Schnelle     DeviceClass *dc = DEVICE_CLASS(klass);
101834ea023dSSven Schnelle     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
101934ea023dSSven Schnelle 
102034ea023dSSven Schnelle     k->realize = pci_tulip_realize;
102134ea023dSSven Schnelle     k->exit = pci_tulip_exit;
102234ea023dSSven Schnelle     k->vendor_id = PCI_VENDOR_ID_DEC;
102334ea023dSSven Schnelle     k->device_id = PCI_DEVICE_ID_DEC_21143;
10242e90154eSHelge Deller     k->subsystem_vendor_id = PCI_VENDOR_ID_HP;
102534ea023dSSven Schnelle     k->subsystem_id = 0x104f;
102634ea023dSSven Schnelle     k->class_id = PCI_CLASS_NETWORK_ETHERNET;
102734ea023dSSven Schnelle     dc->vmsd = &vmstate_pci_tulip;
10284f67d30bSMarc-André Lureau     device_class_set_props(dc, tulip_properties);
1029*e3d08143SPeter Maydell     device_class_set_legacy_reset(dc, tulip_qdev_reset);
103034ea023dSSven Schnelle     set_bit(DEVICE_CATEGORY_NETWORK, dc->categories);
103134ea023dSSven Schnelle }
103234ea023dSSven Schnelle 
103334ea023dSSven Schnelle static const TypeInfo tulip_info = {
103434ea023dSSven Schnelle     .name          = TYPE_TULIP,
103534ea023dSSven Schnelle     .parent        = TYPE_PCI_DEVICE,
103634ea023dSSven Schnelle     .instance_size = sizeof(TULIPState),
103734ea023dSSven Schnelle     .class_init    = tulip_class_init,
103834ea023dSSven Schnelle     .instance_init = tulip_instance_init,
103934ea023dSSven Schnelle     .interfaces = (InterfaceInfo[]) {
104034ea023dSSven Schnelle         { INTERFACE_CONVENTIONAL_PCI_DEVICE },
104134ea023dSSven Schnelle         { },
104234ea023dSSven Schnelle     },
104334ea023dSSven Schnelle };
104434ea023dSSven Schnelle 
tulip_register_types(void)104534ea023dSSven Schnelle static void tulip_register_types(void)
104634ea023dSSven Schnelle {
104734ea023dSSven Schnelle     type_register_static(&tulip_info);
104834ea023dSSven Schnelle }
104934ea023dSSven Schnelle 
105034ea023dSSven Schnelle type_init(tulip_register_types)
1051