Commit 91cc029598b7cd37c726175e05df7e45e9df6ffb
1 parent
c03b0f0f
initial sparc32 lance and pcnet merge
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2142 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
327 additions
and
588 deletions
hw/lance.c deleted
100644 → 0
| 1 | -/* | |
| 2 | - * QEMU Lance emulation | |
| 3 | - * | |
| 4 | - * Copyright (c) 2003-2005 Fabrice Bellard | |
| 5 | - * | |
| 6 | - * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 7 | - * of this software and associated documentation files (the "Software"), to deal | |
| 8 | - * in the Software without restriction, including without limitation the rights | |
| 9 | - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 10 | - * copies of the Software, and to permit persons to whom the Software is | |
| 11 | - * furnished to do so, subject to the following conditions: | |
| 12 | - * | |
| 13 | - * The above copyright notice and this permission notice shall be included in | |
| 14 | - * all copies or substantial portions of the Software. | |
| 15 | - * | |
| 16 | - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 17 | - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 18 | - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| 19 | - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 20 | - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 21 | - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
| 22 | - * THE SOFTWARE. | |
| 23 | - */ | |
| 24 | -#include "vl.h" | |
| 25 | - | |
| 26 | -/* debug LANCE card */ | |
| 27 | -//#define DEBUG_LANCE | |
| 28 | - | |
| 29 | -#ifdef DEBUG_LANCE | |
| 30 | -#define DPRINTF(fmt, args...) \ | |
| 31 | -do { printf("LANCE: " fmt , ##args); } while (0) | |
| 32 | -#else | |
| 33 | -#define DPRINTF(fmt, args...) | |
| 34 | -#endif | |
| 35 | - | |
| 36 | -#ifndef LANCE_LOG_TX_BUFFERS | |
| 37 | -#define LANCE_LOG_TX_BUFFERS 4 | |
| 38 | -#define LANCE_LOG_RX_BUFFERS 4 | |
| 39 | -#endif | |
| 40 | - | |
| 41 | -#define LE_CSR0 0 | |
| 42 | -#define LE_CSR1 1 | |
| 43 | -#define LE_CSR2 2 | |
| 44 | -#define LE_CSR3 3 | |
| 45 | -#define LE_NREGS (LE_CSR3 + 1) | |
| 46 | -#define LE_MAXREG LE_CSR3 | |
| 47 | - | |
| 48 | -#define LE_RDP 0 | |
| 49 | -#define LE_RAP 1 | |
| 50 | - | |
| 51 | -#define LE_MO_PROM 0x8000 /* Enable promiscuous mode */ | |
| 52 | - | |
| 53 | -#define LE_C0_ERR 0x8000 /* Error: set if BAB, SQE, MISS or ME is set */ | |
| 54 | -#define LE_C0_BABL 0x4000 /* BAB: Babble: tx timeout. */ | |
| 55 | -#define LE_C0_CERR 0x2000 /* SQE: Signal quality error */ | |
| 56 | -#define LE_C0_MISS 0x1000 /* MISS: Missed a packet */ | |
| 57 | -#define LE_C0_MERR 0x0800 /* ME: Memory error */ | |
| 58 | -#define LE_C0_RINT 0x0400 /* Received interrupt */ | |
| 59 | -#define LE_C0_TINT 0x0200 /* Transmitter Interrupt */ | |
| 60 | -#define LE_C0_IDON 0x0100 /* IFIN: Init finished. */ | |
| 61 | -#define LE_C0_INTR 0x0080 /* Interrupt or error */ | |
| 62 | -#define LE_C0_INEA 0x0040 /* Interrupt enable */ | |
| 63 | -#define LE_C0_RXON 0x0020 /* Receiver on */ | |
| 64 | -#define LE_C0_TXON 0x0010 /* Transmitter on */ | |
| 65 | -#define LE_C0_TDMD 0x0008 /* Transmitter demand */ | |
| 66 | -#define LE_C0_STOP 0x0004 /* Stop the card */ | |
| 67 | -#define LE_C0_STRT 0x0002 /* Start the card */ | |
| 68 | -#define LE_C0_INIT 0x0001 /* Init the card */ | |
| 69 | - | |
| 70 | -#define LE_C3_BSWP 0x4 /* SWAP */ | |
| 71 | -#define LE_C3_ACON 0x2 /* ALE Control */ | |
| 72 | -#define LE_C3_BCON 0x1 /* Byte control */ | |
| 73 | - | |
| 74 | -/* Receive message descriptor 1 */ | |
| 75 | -#define LE_R1_OWN 0x80 /* Who owns the entry */ | |
| 76 | -#define LE_R1_ERR 0x40 /* Error: if FRA, OFL, CRC or BUF is set */ | |
| 77 | -#define LE_R1_FRA 0x20 /* FRA: Frame error */ | |
| 78 | -#define LE_R1_OFL 0x10 /* OFL: Frame overflow */ | |
| 79 | -#define LE_R1_CRC 0x08 /* CRC error */ | |
| 80 | -#define LE_R1_BUF 0x04 /* BUF: Buffer error */ | |
| 81 | -#define LE_R1_SOP 0x02 /* Start of packet */ | |
| 82 | -#define LE_R1_EOP 0x01 /* End of packet */ | |
| 83 | -#define LE_R1_POK 0x03 /* Packet is complete: SOP + EOP */ | |
| 84 | - | |
| 85 | -#define LE_T1_OWN 0x80 /* Lance owns the packet */ | |
| 86 | -#define LE_T1_ERR 0x40 /* Error summary */ | |
| 87 | -#define LE_T1_EMORE 0x10 /* Error: more than one retry needed */ | |
| 88 | -#define LE_T1_EONE 0x08 /* Error: one retry needed */ | |
| 89 | -#define LE_T1_EDEF 0x04 /* Error: deferred */ | |
| 90 | -#define LE_T1_SOP 0x02 /* Start of packet */ | |
| 91 | -#define LE_T1_EOP 0x01 /* End of packet */ | |
| 92 | -#define LE_T1_POK 0x03 /* Packet is complete: SOP + EOP */ | |
| 93 | - | |
| 94 | -#define LE_T3_BUF 0x8000 /* Buffer error */ | |
| 95 | -#define LE_T3_UFL 0x4000 /* Error underflow */ | |
| 96 | -#define LE_T3_LCOL 0x1000 /* Error late collision */ | |
| 97 | -#define LE_T3_CLOS 0x0800 /* Error carrier loss */ | |
| 98 | -#define LE_T3_RTY 0x0400 /* Error retry */ | |
| 99 | -#define LE_T3_TDR 0x03ff /* Time Domain Reflectometry counter */ | |
| 100 | - | |
| 101 | -#define TX_RING_SIZE (1 << (LANCE_LOG_TX_BUFFERS)) | |
| 102 | -#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) | |
| 103 | -#define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29) | |
| 104 | - | |
| 105 | -#define RX_RING_SIZE (1 << (LANCE_LOG_RX_BUFFERS)) | |
| 106 | -#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) | |
| 107 | -#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29) | |
| 108 | - | |
| 109 | -#define PKT_BUF_SZ 1544 | |
| 110 | -#define RX_BUFF_SIZE PKT_BUF_SZ | |
| 111 | -#define TX_BUFF_SIZE PKT_BUF_SZ | |
| 112 | - | |
| 113 | -struct lance_rx_desc { | |
| 114 | - unsigned short rmd0; /* low address of packet */ | |
| 115 | - unsigned char rmd1_bits; /* descriptor bits */ | |
| 116 | - unsigned char rmd1_hadr; /* high address of packet */ | |
| 117 | - short length; /* This length is 2s complement (negative)! | |
| 118 | - * Buffer length | |
| 119 | - */ | |
| 120 | - unsigned short mblength; /* This is the actual number of bytes received */ | |
| 121 | -}; | |
| 122 | - | |
| 123 | -struct lance_tx_desc { | |
| 124 | - unsigned short tmd0; /* low address of packet */ | |
| 125 | - unsigned char tmd1_bits; /* descriptor bits */ | |
| 126 | - unsigned char tmd1_hadr; /* high address of packet */ | |
| 127 | - short length; /* Length is 2s complement (negative)! */ | |
| 128 | - unsigned short misc; | |
| 129 | -}; | |
| 130 | - | |
| 131 | -/* The LANCE initialization block, described in databook. */ | |
| 132 | -/* On the Sparc, this block should be on a DMA region */ | |
| 133 | -struct lance_init_block { | |
| 134 | - unsigned short mode; /* Pre-set mode (reg. 15) */ | |
| 135 | - unsigned char phys_addr[6]; /* Physical ethernet address */ | |
| 136 | - unsigned filter[2]; /* Multicast filter. */ | |
| 137 | - | |
| 138 | - /* Receive and transmit ring base, along with extra bits. */ | |
| 139 | - unsigned short rx_ptr; /* receive descriptor addr */ | |
| 140 | - unsigned short rx_len; /* receive len and high addr */ | |
| 141 | - unsigned short tx_ptr; /* transmit descriptor addr */ | |
| 142 | - unsigned short tx_len; /* transmit len and high addr */ | |
| 143 | - | |
| 144 | - /* The Tx and Rx ring entries must aligned on 8-byte boundaries. */ | |
| 145 | - struct lance_rx_desc brx_ring[RX_RING_SIZE]; | |
| 146 | - struct lance_tx_desc btx_ring[TX_RING_SIZE]; | |
| 147 | - | |
| 148 | - char tx_buf[TX_RING_SIZE][TX_BUFF_SIZE]; | |
| 149 | - char pad[2]; /* align rx_buf for copy_and_sum(). */ | |
| 150 | - char rx_buf[RX_RING_SIZE][RX_BUFF_SIZE]; | |
| 151 | -}; | |
| 152 | - | |
| 153 | -#define LEDMA_REGS 4 | |
| 154 | -#define LEDMA_MAXADDR (LEDMA_REGS * 4 - 1) | |
| 155 | - | |
| 156 | -typedef struct LANCEState { | |
| 157 | - VLANClientState *vc; | |
| 158 | - uint8_t macaddr[6]; /* init mac address */ | |
| 159 | - uint32_t leptr; | |
| 160 | - uint16_t addr; | |
| 161 | - uint16_t regs[LE_NREGS]; | |
| 162 | - uint8_t phys[6]; /* mac address */ | |
| 163 | - int irq; | |
| 164 | - unsigned int rxptr, txptr; | |
| 165 | - uint32_t ledmaregs[LEDMA_REGS]; | |
| 166 | -} LANCEState; | |
| 167 | - | |
| 168 | -static void lance_send(void *opaque); | |
| 169 | - | |
| 170 | -static void lance_reset(void *opaque) | |
| 171 | -{ | |
| 172 | - LANCEState *s = opaque; | |
| 173 | - memcpy(s->phys, s->macaddr, 6); | |
| 174 | - s->rxptr = 0; | |
| 175 | - s->txptr = 0; | |
| 176 | - memset(s->regs, 0, LE_NREGS * 2); | |
| 177 | - s->regs[LE_CSR0] = LE_C0_STOP; | |
| 178 | - memset(s->ledmaregs, 0, LEDMA_REGS * 4); | |
| 179 | -} | |
| 180 | - | |
| 181 | -static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr) | |
| 182 | -{ | |
| 183 | - LANCEState *s = opaque; | |
| 184 | - uint32_t saddr; | |
| 185 | - | |
| 186 | - saddr = addr & LE_MAXREG; | |
| 187 | - switch (saddr >> 1) { | |
| 188 | - case LE_RDP: | |
| 189 | - DPRINTF("read dreg[%d] = %4.4x\n", s->addr, s->regs[s->addr]); | |
| 190 | - return s->regs[s->addr]; | |
| 191 | - case LE_RAP: | |
| 192 | - DPRINTF("read areg = %4.4x\n", s->addr); | |
| 193 | - return s->addr; | |
| 194 | - default: | |
| 195 | - DPRINTF("read unknown(%d)\n", saddr >> 1); | |
| 196 | - break; | |
| 197 | - } | |
| 198 | - return 0; | |
| 199 | -} | |
| 200 | - | |
| 201 | -static void lance_mem_writew(void *opaque, target_phys_addr_t addr, | |
| 202 | - uint32_t val) | |
| 203 | -{ | |
| 204 | - LANCEState *s = opaque; | |
| 205 | - uint32_t saddr; | |
| 206 | - uint16_t reg; | |
| 207 | - | |
| 208 | - saddr = addr & LE_MAXREG; | |
| 209 | - switch (saddr >> 1) { | |
| 210 | - case LE_RDP: | |
| 211 | - DPRINTF("write dreg[%d] = %4.4x\n", s->addr, val); | |
| 212 | - switch (s->addr) { | |
| 213 | - case LE_CSR0: | |
| 214 | - if (val & LE_C0_STOP) { | |
| 215 | - s->regs[LE_CSR0] = LE_C0_STOP; | |
| 216 | - break; | |
| 217 | - } | |
| 218 | - | |
| 219 | - reg = s->regs[LE_CSR0]; | |
| 220 | - | |
| 221 | - // 1 = clear for some bits | |
| 222 | - reg &= ~(val & 0x7f00); | |
| 223 | - | |
| 224 | - // generated bits | |
| 225 | - reg &= ~(LE_C0_ERR | LE_C0_INTR); | |
| 226 | - if (reg & 0x7100) | |
| 227 | - reg |= LE_C0_ERR; | |
| 228 | - if (reg & 0x7f00) | |
| 229 | - reg |= LE_C0_INTR; | |
| 230 | - | |
| 231 | - // direct bit | |
| 232 | - reg &= ~LE_C0_INEA; | |
| 233 | - reg |= val & LE_C0_INEA; | |
| 234 | - | |
| 235 | - // exclusive bits | |
| 236 | - if (val & LE_C0_INIT) { | |
| 237 | - reg |= LE_C0_IDON | LE_C0_INIT; | |
| 238 | - reg &= ~LE_C0_STOP; | |
| 239 | - } else if (val & LE_C0_STRT) { | |
| 240 | - reg |= LE_C0_STRT | LE_C0_RXON | LE_C0_TXON; | |
| 241 | - reg &= ~LE_C0_STOP; | |
| 242 | - } | |
| 243 | - | |
| 244 | - s->regs[LE_CSR0] = reg; | |
| 245 | - break; | |
| 246 | - case LE_CSR1: | |
| 247 | - s->leptr = (s->leptr & 0xffff0000) | (val & 0xffff); | |
| 248 | - s->regs[s->addr] = val; | |
| 249 | - break; | |
| 250 | - case LE_CSR2: | |
| 251 | - s->leptr = (s->leptr & 0xffff) | ((val & 0xffff) << 16); | |
| 252 | - s->regs[s->addr] = val; | |
| 253 | - break; | |
| 254 | - case LE_CSR3: | |
| 255 | - s->regs[s->addr] = val; | |
| 256 | - break; | |
| 257 | - } | |
| 258 | - break; | |
| 259 | - case LE_RAP: | |
| 260 | - DPRINTF("write areg = %4.4x\n", val); | |
| 261 | - if (val < LE_NREGS) | |
| 262 | - s->addr = val; | |
| 263 | - break; | |
| 264 | - default: | |
| 265 | - DPRINTF("write unknown(%d) = %4.4x\n", saddr >> 1, val); | |
| 266 | - break; | |
| 267 | - } | |
| 268 | - lance_send(s); | |
| 269 | -} | |
| 270 | - | |
| 271 | -static CPUReadMemoryFunc *lance_mem_read[3] = { | |
| 272 | - lance_mem_readw, | |
| 273 | - lance_mem_readw, | |
| 274 | - lance_mem_readw, | |
| 275 | -}; | |
| 276 | - | |
| 277 | -static CPUWriteMemoryFunc *lance_mem_write[3] = { | |
| 278 | - lance_mem_writew, | |
| 279 | - lance_mem_writew, | |
| 280 | - lance_mem_writew, | |
| 281 | -}; | |
| 282 | - | |
| 283 | - | |
| 284 | -#define MIN_BUF_SIZE 60 | |
| 285 | - | |
| 286 | -static int lance_can_receive(void *opaque) | |
| 287 | -{ | |
| 288 | - return 1; | |
| 289 | -} | |
| 290 | - | |
| 291 | -static void lance_receive(void *opaque, const uint8_t * buf, int size) | |
| 292 | -{ | |
| 293 | - LANCEState *s = opaque; | |
| 294 | - uint32_t dmaptr = s->leptr + s->ledmaregs[3]; | |
| 295 | - struct lance_init_block *ib; | |
| 296 | - unsigned int i, old_rxptr; | |
| 297 | - uint16_t temp16; | |
| 298 | - uint8_t temp8; | |
| 299 | - | |
| 300 | - DPRINTF("receive size %d\n", size); | |
| 301 | - if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP) | |
| 302 | - return; | |
| 303 | - | |
| 304 | - ib = (void *) iommu_translate(dmaptr); | |
| 305 | - | |
| 306 | - old_rxptr = s->rxptr; | |
| 307 | - for (i = s->rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); | |
| 308 | - i = (i + 1) & RX_RING_MOD_MASK) { | |
| 309 | - cpu_physical_memory_read((uint32_t) & ib->brx_ring[i].rmd1_bits, | |
| 310 | - (void *) &temp8, 1); | |
| 311 | - if (temp8 == (LE_R1_OWN)) { | |
| 312 | - s->rxptr = (s->rxptr + 1) & RX_RING_MOD_MASK; | |
| 313 | - temp16 = size + 4; | |
| 314 | - bswap16s(&temp16); | |
| 315 | - cpu_physical_memory_write((uint32_t) & ib->brx_ring[i]. | |
| 316 | - mblength, (void *) &temp16, 2); | |
| 317 | - cpu_physical_memory_write((uint32_t) & ib->rx_buf[i], buf, | |
| 318 | - size); | |
| 319 | - temp8 = LE_R1_POK; | |
| 320 | - cpu_physical_memory_write((uint32_t) & ib->brx_ring[i]. | |
| 321 | - rmd1_bits, (void *) &temp8, 1); | |
| 322 | - s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR; | |
| 323 | - if (s->regs[LE_CSR0] & LE_C0_INEA) | |
| 324 | - pic_set_irq(s->irq, 1); | |
| 325 | - DPRINTF("got packet, len %d\n", size); | |
| 326 | - return; | |
| 327 | - } | |
| 328 | - } | |
| 329 | -} | |
| 330 | - | |
| 331 | -static void lance_send(void *opaque) | |
| 332 | -{ | |
| 333 | - LANCEState *s = opaque; | |
| 334 | - uint32_t dmaptr = s->leptr + s->ledmaregs[3]; | |
| 335 | - struct lance_init_block *ib; | |
| 336 | - unsigned int i, old_txptr; | |
| 337 | - uint16_t temp16; | |
| 338 | - uint8_t temp8; | |
| 339 | - char pkt_buf[PKT_BUF_SZ]; | |
| 340 | - | |
| 341 | - DPRINTF("sending packet? (csr0 %4.4x)\n", s->regs[LE_CSR0]); | |
| 342 | - if ((s->regs[LE_CSR0] & LE_C0_STOP) == LE_C0_STOP) | |
| 343 | - return; | |
| 344 | - | |
| 345 | - ib = (void *) iommu_translate(dmaptr); | |
| 346 | - | |
| 347 | - DPRINTF("sending packet? (dmaptr %8.8x) (ib %p) (btx_ring %p)\n", | |
| 348 | - dmaptr, ib, &ib->btx_ring); | |
| 349 | - old_txptr = s->txptr; | |
| 350 | - for (i = s->txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); | |
| 351 | - i = (i + 1) & TX_RING_MOD_MASK) { | |
| 352 | - cpu_physical_memory_read((uint32_t) & ib->btx_ring[i].tmd1_bits, | |
| 353 | - (void *) &temp8, 1); | |
| 354 | - if (temp8 == (LE_T1_POK | LE_T1_OWN)) { | |
| 355 | - cpu_physical_memory_read((uint32_t) & ib->btx_ring[i].length, | |
| 356 | - (void *) &temp16, 2); | |
| 357 | - bswap16s(&temp16); | |
| 358 | - temp16 = (~temp16) + 1; | |
| 359 | - cpu_physical_memory_read((uint32_t) & ib->tx_buf[i], pkt_buf, | |
| 360 | - temp16); | |
| 361 | - DPRINTF("sending packet, len %d\n", temp16); | |
| 362 | - qemu_send_packet(s->vc, pkt_buf, temp16); | |
| 363 | - temp8 = LE_T1_POK; | |
| 364 | - cpu_physical_memory_write((uint32_t) & ib->btx_ring[i]. | |
| 365 | - tmd1_bits, (void *) &temp8, 1); | |
| 366 | - s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK; | |
| 367 | - s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR; | |
| 368 | - } | |
| 369 | - } | |
| 370 | - if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA)) | |
| 371 | - pic_set_irq(s->irq, 1); | |
| 372 | -} | |
| 373 | - | |
| 374 | -static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr) | |
| 375 | -{ | |
| 376 | - LANCEState *s = opaque; | |
| 377 | - uint32_t saddr; | |
| 378 | - | |
| 379 | - saddr = (addr & LEDMA_MAXADDR) >> 2; | |
| 380 | - return s->ledmaregs[saddr]; | |
| 381 | -} | |
| 382 | - | |
| 383 | -static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, | |
| 384 | - uint32_t val) | |
| 385 | -{ | |
| 386 | - LANCEState *s = opaque; | |
| 387 | - uint32_t saddr; | |
| 388 | - | |
| 389 | - saddr = (addr & LEDMA_MAXADDR) >> 2; | |
| 390 | - s->ledmaregs[saddr] = val; | |
| 391 | -} | |
| 392 | - | |
| 393 | -static CPUReadMemoryFunc *ledma_mem_read[3] = { | |
| 394 | - ledma_mem_readl, | |
| 395 | - ledma_mem_readl, | |
| 396 | - ledma_mem_readl, | |
| 397 | -}; | |
| 398 | - | |
| 399 | -static CPUWriteMemoryFunc *ledma_mem_write[3] = { | |
| 400 | - ledma_mem_writel, | |
| 401 | - ledma_mem_writel, | |
| 402 | - ledma_mem_writel, | |
| 403 | -}; | |
| 404 | - | |
| 405 | -static void lance_save(QEMUFile * f, void *opaque) | |
| 406 | -{ | |
| 407 | - LANCEState *s = opaque; | |
| 408 | - int i; | |
| 409 | - | |
| 410 | - qemu_put_be32s(f, &s->leptr); | |
| 411 | - qemu_put_be16s(f, &s->addr); | |
| 412 | - for (i = 0; i < LE_NREGS; i++) | |
| 413 | - qemu_put_be16s(f, &s->regs[i]); | |
| 414 | - qemu_put_buffer(f, s->phys, 6); | |
| 415 | - qemu_put_be32s(f, &s->irq); | |
| 416 | - for (i = 0; i < LEDMA_REGS; i++) | |
| 417 | - qemu_put_be32s(f, &s->ledmaregs[i]); | |
| 418 | -} | |
| 419 | - | |
| 420 | -static int lance_load(QEMUFile * f, void *opaque, int version_id) | |
| 421 | -{ | |
| 422 | - LANCEState *s = opaque; | |
| 423 | - int i; | |
| 424 | - | |
| 425 | - if (version_id != 1) | |
| 426 | - return -EINVAL; | |
| 427 | - | |
| 428 | - qemu_get_be32s(f, &s->leptr); | |
| 429 | - qemu_get_be16s(f, &s->addr); | |
| 430 | - for (i = 0; i < LE_NREGS; i++) | |
| 431 | - qemu_get_be16s(f, &s->regs[i]); | |
| 432 | - qemu_get_buffer(f, s->phys, 6); | |
| 433 | - qemu_get_be32s(f, &s->irq); | |
| 434 | - for (i = 0; i < LEDMA_REGS; i++) | |
| 435 | - qemu_get_be32s(f, &s->ledmaregs[i]); | |
| 436 | - return 0; | |
| 437 | -} | |
| 438 | - | |
| 439 | -void lance_init(NICInfo * nd, int irq, uint32_t leaddr, uint32_t ledaddr) | |
| 440 | -{ | |
| 441 | - LANCEState *s; | |
| 442 | - int lance_io_memory, ledma_io_memory; | |
| 443 | - | |
| 444 | - s = qemu_mallocz(sizeof(LANCEState)); | |
| 445 | - if (!s) | |
| 446 | - return; | |
| 447 | - | |
| 448 | - s->irq = irq; | |
| 449 | - | |
| 450 | - lance_io_memory = | |
| 451 | - cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s); | |
| 452 | - cpu_register_physical_memory(leaddr, 4, lance_io_memory); | |
| 453 | - | |
| 454 | - ledma_io_memory = | |
| 455 | - cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s); | |
| 456 | - cpu_register_physical_memory(ledaddr, 16, ledma_io_memory); | |
| 457 | - | |
| 458 | - memcpy(s->macaddr, nd->macaddr, 6); | |
| 459 | - | |
| 460 | - lance_reset(s); | |
| 461 | - | |
| 462 | - s->vc = | |
| 463 | - qemu_new_vlan_client(nd->vlan, lance_receive, lance_can_receive, | |
| 464 | - s); | |
| 465 | - | |
| 466 | - snprintf(s->vc->info_str, sizeof(s->vc->info_str), | |
| 467 | - "lance macaddr=%02x:%02x:%02x:%02x:%02x:%02x", | |
| 468 | - s->macaddr[0], | |
| 469 | - s->macaddr[1], | |
| 470 | - s->macaddr[2], s->macaddr[3], s->macaddr[4], s->macaddr[5]); | |
| 471 | - | |
| 472 | - register_savevm("lance", leaddr, 1, lance_save, lance_load, s); | |
| 473 | - qemu_register_reset(lance_reset, s); | |
| 474 | -} |
hw/pcnet.c
| ... | ... | @@ -27,6 +27,16 @@ |
| 27 | 27 | * AMD Publication# 19436 Rev:E Amendment/0 Issue Date: June 2000 |
| 28 | 28 | */ |
| 29 | 29 | |
| 30 | +/* | |
| 31 | + * On Sparc32, this is the Lance (Am7990) part of chip STP2000 (Master I/O), also | |
| 32 | + * produced as NCR89C100. See | |
| 33 | + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C100.txt | |
| 34 | + * and | |
| 35 | + * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR92C990.txt | |
| 36 | + */ | |
| 37 | + | |
| 38 | +/* TODO: remove little endian host assumptions */ | |
| 39 | + | |
| 30 | 40 | #include "vl.h" |
| 31 | 41 | |
| 32 | 42 | //#define PCNET_DEBUG |
| ... | ... | @@ -46,11 +56,12 @@ typedef struct PCNetState_st PCNetState; |
| 46 | 56 | |
| 47 | 57 | struct PCNetState_st { |
| 48 | 58 | PCIDevice dev; |
| 59 | + PCIDevice *pci_dev; | |
| 49 | 60 | VLANClientState *vc; |
| 50 | 61 | NICInfo *nd; |
| 51 | 62 | QEMUTimer *poll_timer; |
| 52 | - int mmio_io_addr, rap, isr, lnkst; | |
| 53 | - target_phys_addr_t rdra, tdra; | |
| 63 | + int mmio_index, rap, isr, lnkst; | |
| 64 | + uint32_t rdra, tdra; | |
| 54 | 65 | uint8_t prom[16]; |
| 55 | 66 | uint16_t csr[128]; |
| 56 | 67 | uint16_t bcr[32]; |
| ... | ... | @@ -58,6 +69,12 @@ struct PCNetState_st { |
| 58 | 69 | int xmit_pos, recv_pos; |
| 59 | 70 | uint8_t buffer[4096]; |
| 60 | 71 | int tx_busy; |
| 72 | + void (*set_irq_cb)(void *s, int isr); | |
| 73 | + void (*phys_mem_read)(void *dma_opaque, target_phys_addr_t addr, | |
| 74 | + uint8_t *buf, int len); | |
| 75 | + void (*phys_mem_write)(void *dma_opaque, target_phys_addr_t addr, | |
| 76 | + uint8_t *buf, int len); | |
| 77 | + void *dma_opaque; | |
| 61 | 78 | }; |
| 62 | 79 | |
| 63 | 80 | /* XXX: using bitfields for target memory structures is almost surely |
| ... | ... | @@ -99,6 +116,7 @@ struct qemu_ether_header { |
| 99 | 116 | #define CSR_TXON(S) !!(((S)->csr[0])&0x0010) |
| 100 | 117 | #define CSR_RXON(S) !!(((S)->csr[0])&0x0020) |
| 101 | 118 | #define CSR_INEA(S) !!(((S)->csr[0])&0x0040) |
| 119 | +#define CSR_BIGENDIAN(S) !!(((S)->csr[3])&0x0004) | |
| 102 | 120 | #define CSR_LAPPEN(S) !!(((S)->csr[3])&0x0020) |
| 103 | 121 | #define CSR_DXSUFLO(S) !!(((S)->csr[3])&0x0040) |
| 104 | 122 | #define CSR_ASTRP_RCV(S) !!(((S)->csr[4])&0x0800) |
| ... | ... | @@ -147,35 +165,19 @@ struct qemu_ether_header { |
| 147 | 165 | |
| 148 | 166 | struct pcnet_initblk16 { |
| 149 | 167 | uint16_t mode; |
| 150 | - uint16_t padr1; | |
| 151 | - uint16_t padr2; | |
| 152 | - uint16_t padr3; | |
| 153 | - uint16_t ladrf1; | |
| 154 | - uint16_t ladrf2; | |
| 155 | - uint16_t ladrf3; | |
| 156 | - uint16_t ladrf4; | |
| 157 | - unsigned PACKED_FIELD(rdra:24); | |
| 158 | - unsigned PACKED_FIELD(res1:5); | |
| 159 | - unsigned PACKED_FIELD(rlen:3); | |
| 160 | - unsigned PACKED_FIELD(tdra:24); | |
| 161 | - unsigned PACKED_FIELD(res2:5); | |
| 162 | - unsigned PACKED_FIELD(tlen:3); | |
| 168 | + uint16_t padr[3]; | |
| 169 | + uint16_t ladrf[4]; | |
| 170 | + uint32_t rdra; | |
| 171 | + uint32_t tdra; | |
| 163 | 172 | }; |
| 164 | 173 | |
| 165 | 174 | struct pcnet_initblk32 { |
| 166 | 175 | uint16_t mode; |
| 167 | - unsigned PACKED_FIELD(res1:4); | |
| 168 | - unsigned PACKED_FIELD(rlen:4); | |
| 169 | - unsigned PACKED_FIELD(res2:4); | |
| 170 | - unsigned PACKED_FIELD(tlen:4); | |
| 171 | - uint16_t padr1; | |
| 172 | - uint16_t padr2; | |
| 173 | - uint16_t padr3; | |
| 176 | + uint8_t rlen; | |
| 177 | + uint8_t tlen; | |
| 178 | + uint16_t padr[3]; | |
| 174 | 179 | uint16_t _res; |
| 175 | - uint16_t ladrf1; | |
| 176 | - uint16_t ladrf2; | |
| 177 | - uint16_t ladrf3; | |
| 178 | - uint16_t ladrf4; | |
| 180 | + uint16_t ladrf[4]; | |
| 179 | 181 | uint32_t rdra; |
| 180 | 182 | uint32_t tdra; |
| 181 | 183 | }; |
| ... | ... | @@ -255,22 +257,32 @@ static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd, target_p |
| 255 | 257 | { |
| 256 | 258 | if (!BCR_SWSTYLE(s)) { |
| 257 | 259 | uint16_t xda[4]; |
| 258 | - cpu_physical_memory_read(addr, | |
| 260 | + s->phys_mem_read(s->dma_opaque, addr, | |
| 259 | 261 | (void *)&xda[0], sizeof(xda)); |
| 260 | - ((uint32_t *)tmd)[0] = (xda[0]&0xffff) | | |
| 262 | + if (CSR_BIGENDIAN(s)) { | |
| 263 | + ((uint32_t *)tmd)[0] = be16_to_cpu(xda[0]) | | |
| 264 | + ((be16_to_cpu(xda[1]) & 0x00ff) << 16); | |
| 265 | + ((uint32_t *)tmd)[1] = be16_to_cpu(xda[2]) | | |
| 266 | + ((be16_to_cpu(xda[1]) & 0xff00) << 16); | |
| 267 | + ((uint32_t *)tmd)[2] = | |
| 268 | + (be16_to_cpu(xda[3]) & 0xffff) << 16; | |
| 269 | + ((uint32_t *)tmd)[3] = 0; | |
| 270 | + } else { | |
| 271 | + ((uint32_t *)tmd)[0] = (xda[0]&0xffff) | | |
| 261 | 272 | ((xda[1]&0x00ff) << 16); |
| 262 | - ((uint32_t *)tmd)[1] = (xda[2]&0xffff)| | |
| 273 | + ((uint32_t *)tmd)[1] = (xda[2]&0xffff)| | |
| 263 | 274 | ((xda[1] & 0xff00) << 16); |
| 264 | - ((uint32_t *)tmd)[2] = | |
| 275 | + ((uint32_t *)tmd)[2] = | |
| 265 | 276 | (xda[3] & 0xffff) << 16; |
| 266 | - ((uint32_t *)tmd)[3] = 0; | |
| 277 | + ((uint32_t *)tmd)[3] = 0; | |
| 278 | + } | |
| 267 | 279 | } |
| 268 | 280 | else |
| 269 | 281 | if (BCR_SWSTYLE(s) != 3) |
| 270 | - cpu_physical_memory_read(addr, (void *)tmd, 16); | |
| 282 | + s->phys_mem_read(s->dma_opaque, addr, (void *)tmd, 16); | |
| 271 | 283 | else { |
| 272 | 284 | uint32_t xda[4]; |
| 273 | - cpu_physical_memory_read(addr, | |
| 285 | + s->phys_mem_read(s->dma_opaque, addr, | |
| 274 | 286 | (void *)&xda[0], sizeof(xda)); |
| 275 | 287 | ((uint32_t *)tmd)[0] = xda[2]; |
| 276 | 288 | ((uint32_t *)tmd)[1] = xda[1]; |
| ... | ... | @@ -283,24 +295,32 @@ static inline void pcnet_tmd_store(PCNetState *s, struct pcnet_TMD *tmd, target_ |
| 283 | 295 | { |
| 284 | 296 | if (!BCR_SWSTYLE(s)) { |
| 285 | 297 | uint16_t xda[4]; |
| 286 | - xda[0] = ((uint32_t *)tmd)[0] & 0xffff; | |
| 287 | - xda[1] = ((((uint32_t *)tmd)[0]>>16)&0x00ff) | | |
| 288 | - ((((uint32_t *)tmd)[1]>>16)&0xff00); | |
| 289 | - xda[2] = ((uint32_t *)tmd)[1] & 0xffff; | |
| 290 | - xda[3] = ((uint32_t *)tmd)[2] >> 16; | |
| 291 | - cpu_physical_memory_write(addr, | |
| 298 | + if (CSR_BIGENDIAN(s)) { | |
| 299 | + xda[0] = cpu_to_be16(((uint32_t *)tmd)[0] & 0xffff); | |
| 300 | + xda[1] = cpu_to_be16(((((uint32_t *)tmd)[0] >> 16) & 0x00ff) | | |
| 301 | + ((((uint32_t *)tmd)[1] >> 16) & 0xff00)); | |
| 302 | + xda[2] = cpu_to_be16(((uint32_t *)tmd)[1] & 0xffff); | |
| 303 | + xda[3] = cpu_to_be16(((uint32_t *)tmd)[2] >> 16); | |
| 304 | + } else { | |
| 305 | + xda[0] = ((uint32_t *)tmd)[0] & 0xffff; | |
| 306 | + xda[1] = ((((uint32_t *)tmd)[0]>>16)&0x00ff) | | |
| 307 | + ((((uint32_t *)tmd)[1]>>16)&0xff00); | |
| 308 | + xda[2] = ((uint32_t *)tmd)[1] & 0xffff; | |
| 309 | + xda[3] = ((uint32_t *)tmd)[2] >> 16; | |
| 310 | + } | |
| 311 | + s->phys_mem_write(s->dma_opaque, addr, | |
| 292 | 312 | (void *)&xda[0], sizeof(xda)); |
| 293 | 313 | } |
| 294 | 314 | else { |
| 295 | 315 | if (BCR_SWSTYLE(s) != 3) |
| 296 | - cpu_physical_memory_write(addr, (void *)tmd, 16); | |
| 316 | + s->phys_mem_write(s->dma_opaque, addr, (void *)tmd, 16); | |
| 297 | 317 | else { |
| 298 | 318 | uint32_t xda[4]; |
| 299 | 319 | xda[0] = ((uint32_t *)tmd)[2]; |
| 300 | 320 | xda[1] = ((uint32_t *)tmd)[1]; |
| 301 | 321 | xda[2] = ((uint32_t *)tmd)[0]; |
| 302 | 322 | xda[3] = ((uint32_t *)tmd)[3]; |
| 303 | - cpu_physical_memory_write(addr, | |
| 323 | + s->phys_mem_write(s->dma_opaque, addr, | |
| 304 | 324 | (void *)&xda[0], sizeof(xda)); |
| 305 | 325 | } |
| 306 | 326 | } |
| ... | ... | @@ -310,21 +330,30 @@ static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd, target_p |
| 310 | 330 | { |
| 311 | 331 | if (!BCR_SWSTYLE(s)) { |
| 312 | 332 | uint16_t rda[4]; |
| 313 | - cpu_physical_memory_read(addr, | |
| 333 | + s->phys_mem_read(s->dma_opaque, addr, | |
| 314 | 334 | (void *)&rda[0], sizeof(rda)); |
| 315 | - ((uint32_t *)rmd)[0] = (rda[0]&0xffff)| | |
| 335 | + if (CSR_BIGENDIAN(s)) { | |
| 336 | + ((uint32_t *)rmd)[0] = (be16_to_cpu(rda[0]) & 0xffff) | | |
| 337 | + ((be16_to_cpu(rda[1]) & 0x00ff) << 16); | |
| 338 | + ((uint32_t *)rmd)[1] = (be16_to_cpu(rda[2]) & 0xffff) | | |
| 339 | + ((be16_to_cpu(rda[1]) & 0xff00) << 16); | |
| 340 | + ((uint32_t *)rmd)[2] = be16_to_cpu(rda[3]) & 0xffff; | |
| 341 | + ((uint32_t *)rmd)[3] = 0; | |
| 342 | + } else { | |
| 343 | + ((uint32_t *)rmd)[0] = (rda[0]&0xffff)| | |
| 316 | 344 | ((rda[1] & 0x00ff) << 16); |
| 317 | - ((uint32_t *)rmd)[1] = (rda[2]&0xffff)| | |
| 345 | + ((uint32_t *)rmd)[1] = (rda[2]&0xffff)| | |
| 318 | 346 | ((rda[1] & 0xff00) << 16); |
| 319 | - ((uint32_t *)rmd)[2] = rda[3] & 0xffff; | |
| 320 | - ((uint32_t *)rmd)[3] = 0; | |
| 347 | + ((uint32_t *)rmd)[2] = rda[3] & 0xffff; | |
| 348 | + ((uint32_t *)rmd)[3] = 0; | |
| 349 | + } | |
| 321 | 350 | } |
| 322 | 351 | else |
| 323 | 352 | if (BCR_SWSTYLE(s) != 3) |
| 324 | - cpu_physical_memory_read(addr, (void *)rmd, 16); | |
| 353 | + s->phys_mem_read(s->dma_opaque, addr, (void *)rmd, 16); | |
| 325 | 354 | else { |
| 326 | 355 | uint32_t rda[4]; |
| 327 | - cpu_physical_memory_read(addr, | |
| 356 | + s->phys_mem_read(s->dma_opaque, addr, | |
| 328 | 357 | (void *)&rda[0], sizeof(rda)); |
| 329 | 358 | ((uint32_t *)rmd)[0] = rda[2]; |
| 330 | 359 | ((uint32_t *)rmd)[1] = rda[1]; |
| ... | ... | @@ -336,25 +365,33 @@ static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd, target_p |
| 336 | 365 | static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_phys_addr_t addr) |
| 337 | 366 | { |
| 338 | 367 | if (!BCR_SWSTYLE(s)) { |
| 339 | - uint16_t rda[4]; \ | |
| 340 | - rda[0] = ((uint32_t *)rmd)[0] & 0xffff; \ | |
| 341 | - rda[1] = ((((uint32_t *)rmd)[0]>>16)&0xff)|\ | |
| 342 | - ((((uint32_t *)rmd)[1]>>16)&0xff00);\ | |
| 343 | - rda[2] = ((uint32_t *)rmd)[1] & 0xffff; \ | |
| 344 | - rda[3] = ((uint32_t *)rmd)[2] & 0xffff; \ | |
| 345 | - cpu_physical_memory_write(addr, \ | |
| 346 | - (void *)&rda[0], sizeof(rda)); \ | |
| 368 | + uint16_t rda[4]; | |
| 369 | + if (CSR_BIGENDIAN(s)) { | |
| 370 | + rda[0] = cpu_to_be16(((uint32_t *)rmd)[0] & 0xffff); | |
| 371 | + rda[1] = cpu_to_be16(((((uint32_t *)rmd)[0] >> 16) & 0xff) | | |
| 372 | + ((((uint32_t *)rmd)[1] >> 16) & 0xff00)); | |
| 373 | + rda[2] = cpu_to_be16(((uint32_t *)rmd)[1] & 0xffff); | |
| 374 | + rda[3] = cpu_to_be16(((uint32_t *)rmd)[2] & 0xffff); | |
| 375 | + } else { | |
| 376 | + rda[0] = ((uint32_t *)rmd)[0] & 0xffff; | |
| 377 | + rda[1] = ((((uint32_t *)rmd)[0]>>16)&0xff)| | |
| 378 | + ((((uint32_t *)rmd)[1]>>16)&0xff00); | |
| 379 | + rda[2] = ((uint32_t *)rmd)[1] & 0xffff; | |
| 380 | + rda[3] = ((uint32_t *)rmd)[2] & 0xffff; | |
| 381 | + } | |
| 382 | + s->phys_mem_write(s->dma_opaque, addr, | |
| 383 | + (void *)&rda[0], sizeof(rda)); | |
| 347 | 384 | } |
| 348 | 385 | else { |
| 349 | 386 | if (BCR_SWSTYLE(s) != 3) |
| 350 | - cpu_physical_memory_write(addr, (void *)rmd, 16); | |
| 387 | + s->phys_mem_write(s->dma_opaque, addr, (void *)rmd, 16); | |
| 351 | 388 | else { |
| 352 | 389 | uint32_t rda[4]; |
| 353 | 390 | rda[0] = ((uint32_t *)rmd)[2]; |
| 354 | 391 | rda[1] = ((uint32_t *)rmd)[1]; |
| 355 | 392 | rda[2] = ((uint32_t *)rmd)[0]; |
| 356 | 393 | rda[3] = ((uint32_t *)rmd)[3]; |
| 357 | - cpu_physical_memory_write(addr, | |
| 394 | + s->phys_mem_write(s->dma_opaque, addr, | |
| 358 | 395 | (void *)&rda[0], sizeof(rda)); |
| 359 | 396 | } |
| 360 | 397 | } |
| ... | ... | @@ -391,7 +428,7 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_ |
| 391 | 428 | case 0x00: \ |
| 392 | 429 | do { \ |
| 393 | 430 | uint16_t rda[4]; \ |
| 394 | - cpu_physical_memory_read((ADDR), \ | |
| 431 | + s->phys_mem_read(s->dma_opaque, (ADDR), \ | |
| 395 | 432 | (void *)&rda[0], sizeof(rda)); \ |
| 396 | 433 | (RES) |= (rda[2] & 0xf000)!=0xf000; \ |
| 397 | 434 | (RES) |= (rda[3] & 0xf000)!=0x0000; \ |
| ... | ... | @@ -401,7 +438,7 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_ |
| 401 | 438 | case 0x02: \ |
| 402 | 439 | do { \ |
| 403 | 440 | uint32_t rda[4]; \ |
| 404 | - cpu_physical_memory_read((ADDR), \ | |
| 441 | + s->phys_mem_read(s->dma_opaque, (ADDR), \ | |
| 405 | 442 | (void *)&rda[0], sizeof(rda)); \ |
| 406 | 443 | (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ |
| 407 | 444 | (RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \ |
| ... | ... | @@ -410,7 +447,7 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_ |
| 410 | 447 | case 0x03: \ |
| 411 | 448 | do { \ |
| 412 | 449 | uint32_t rda[4]; \ |
| 413 | - cpu_physical_memory_read((ADDR), \ | |
| 450 | + s->phys_mem_read(s->dma_opaque, (ADDR), \ | |
| 414 | 451 | (void *)&rda[0], sizeof(rda)); \ |
| 415 | 452 | (RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \ |
| 416 | 453 | (RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \ |
| ... | ... | @@ -424,7 +461,7 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_ |
| 424 | 461 | case 0x00: \ |
| 425 | 462 | do { \ |
| 426 | 463 | uint16_t xda[4]; \ |
| 427 | - cpu_physical_memory_read((ADDR), \ | |
| 464 | + s->phys_mem_read(s->dma_opaque, (ADDR), \ | |
| 428 | 465 | (void *)&xda[0], sizeof(xda)); \ |
| 429 | 466 | (RES) |= (xda[2] & 0xf000)!=0xf000;\ |
| 430 | 467 | } while (0); \ |
| ... | ... | @@ -434,7 +471,7 @@ static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd, target_ |
| 434 | 471 | case 0x03: \ |
| 435 | 472 | do { \ |
| 436 | 473 | uint32_t xda[4]; \ |
| 437 | - cpu_physical_memory_read((ADDR), \ | |
| 474 | + s->phys_mem_read(s->dma_opaque, (ADDR), \ | |
| 438 | 475 | (void *)&xda[0], sizeof(xda)); \ |
| 439 | 476 | (RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \ |
| 440 | 477 | } while (0); \ |
| ... | ... | @@ -721,51 +758,86 @@ static void pcnet_update_irq(PCNetState *s) |
| 721 | 758 | printf("pcnet: INTA=%d\n", isr); |
| 722 | 759 | #endif |
| 723 | 760 | } |
| 724 | - pci_set_irq(&s->dev, 0, isr); | |
| 725 | - s->isr = isr; | |
| 761 | + s->set_irq_cb(s, isr); | |
| 762 | + s->isr = isr; | |
| 726 | 763 | } |
| 727 | 764 | |
| 728 | 765 | static void pcnet_init(PCNetState *s) |
| 729 | 766 | { |
| 767 | + int rlen, tlen; | |
| 768 | + uint16_t *padr, *ladrf, mode; | |
| 769 | + uint32_t rdra, tdra; | |
| 770 | + | |
| 730 | 771 | #ifdef PCNET_DEBUG |
| 731 | 772 | printf("pcnet_init init_addr=0x%08x\n", PHYSADDR(s,CSR_IADR(s))); |
| 732 | 773 | #endif |
| 733 | 774 | |
| 734 | -#define PCNET_INIT() do { \ | |
| 735 | - cpu_physical_memory_read(PHYSADDR(s,CSR_IADR(s)), \ | |
| 736 | - (uint8_t *)&initblk, sizeof(initblk)); \ | |
| 737 | - s->csr[15] = le16_to_cpu(initblk.mode); \ | |
| 738 | - CSR_RCVRL(s) = (initblk.rlen < 9) ? (1 << initblk.rlen) : 512; \ | |
| 739 | - CSR_XMTRL(s) = (initblk.tlen < 9) ? (1 << initblk.tlen) : 512; \ | |
| 740 | - s->csr[ 6] = (initblk.tlen << 12) | (initblk.rlen << 8); \ | |
| 741 | - s->csr[ 8] = le16_to_cpu(initblk.ladrf1); \ | |
| 742 | - s->csr[ 9] = le16_to_cpu(initblk.ladrf2); \ | |
| 743 | - s->csr[10] = le16_to_cpu(initblk.ladrf3); \ | |
| 744 | - s->csr[11] = le16_to_cpu(initblk.ladrf4); \ | |
| 745 | - s->csr[12] = le16_to_cpu(initblk.padr1); \ | |
| 746 | - s->csr[13] = le16_to_cpu(initblk.padr2); \ | |
| 747 | - s->csr[14] = le16_to_cpu(initblk.padr3); \ | |
| 748 | - s->rdra = PHYSADDR(s,initblk.rdra); \ | |
| 749 | - s->tdra = PHYSADDR(s,initblk.tdra); \ | |
| 750 | -} while (0) | |
| 751 | - | |
| 752 | 775 | if (BCR_SSIZE32(s)) { |
| 753 | 776 | struct pcnet_initblk32 initblk; |
| 754 | - PCNET_INIT(); | |
| 755 | -#ifdef PCNET_DEBUG | |
| 756 | - printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n", | |
| 757 | - initblk.rlen, initblk.tlen); | |
| 758 | -#endif | |
| 777 | + s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)), | |
| 778 | + (uint8_t *)&initblk, sizeof(initblk)); | |
| 779 | + mode = initblk.mode; | |
| 780 | + rlen = initblk.rlen >> 4; | |
| 781 | + tlen = initblk.tlen >> 4; | |
| 782 | + ladrf = initblk.ladrf; | |
| 783 | + padr = initblk.padr; | |
| 784 | + if (CSR_BIGENDIAN(s)) { | |
| 785 | + rdra = be32_to_cpu(initblk.rdra); | |
| 786 | + tdra = be32_to_cpu(initblk.tdra); | |
| 787 | + } else { | |
| 788 | + rdra = le32_to_cpu(initblk.rdra); | |
| 789 | + tdra = le32_to_cpu(initblk.tdra); | |
| 790 | + } | |
| 791 | + s->rdra = PHYSADDR(s,initblk.rdra); | |
| 792 | + s->tdra = PHYSADDR(s,initblk.tdra); | |
| 759 | 793 | } else { |
| 760 | 794 | struct pcnet_initblk16 initblk; |
| 761 | - PCNET_INIT(); | |
| 762 | -#ifdef PCNET_DEBUG | |
| 763 | - printf("initblk.rlen=0x%02x, initblk.tlen=0x%02x\n", | |
| 764 | - initblk.rlen, initblk.tlen); | |
| 795 | + s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)), | |
| 796 | + (uint8_t *)&initblk, sizeof(initblk)); | |
| 797 | + mode = initblk.mode; | |
| 798 | + ladrf = initblk.ladrf; | |
| 799 | + padr = initblk.padr; | |
| 800 | + if (CSR_BIGENDIAN(s)) { | |
| 801 | + rdra = be32_to_cpu(initblk.rdra); | |
| 802 | + tdra = be32_to_cpu(initblk.tdra); | |
| 803 | + } else { | |
| 804 | + rdra = le32_to_cpu(initblk.rdra); | |
| 805 | + tdra = le32_to_cpu(initblk.tdra); | |
| 806 | + } | |
| 807 | + rlen = rdra >> 29; | |
| 808 | + tlen = tdra >> 29; | |
| 809 | + rdra &= 0x00ffffff; | |
| 810 | + tdra &= 0x00ffffff; | |
| 811 | + } | |
| 812 | + | |
| 813 | +#if defined(PCNET_DEBUG) | |
| 814 | + printf("rlen=%d tlen=%d\n", | |
| 815 | + rlen, tlen); | |
| 765 | 816 | #endif |
| 817 | + CSR_RCVRL(s) = (rlen < 9) ? (1 << rlen) : 512; | |
| 818 | + CSR_XMTRL(s) = (tlen < 9) ? (1 << tlen) : 512; | |
| 819 | + s->csr[ 6] = (tlen << 12) | (rlen << 8); | |
| 820 | + if (CSR_BIGENDIAN(s)) { | |
| 821 | + s->csr[15] = be16_to_cpu(mode); | |
| 822 | + s->csr[ 8] = be16_to_cpu(ladrf[0]); | |
| 823 | + s->csr[ 9] = be16_to_cpu(ladrf[1]); | |
| 824 | + s->csr[10] = be16_to_cpu(ladrf[2]); | |
| 825 | + s->csr[11] = be16_to_cpu(ladrf[3]); | |
| 826 | + s->csr[12] = be16_to_cpu(padr[0]); | |
| 827 | + s->csr[13] = be16_to_cpu(padr[1]); | |
| 828 | + s->csr[14] = be16_to_cpu(padr[2]); | |
| 829 | + } else { | |
| 830 | + s->csr[15] = le16_to_cpu(mode); | |
| 831 | + s->csr[ 8] = le16_to_cpu(ladrf[0]); | |
| 832 | + s->csr[ 9] = le16_to_cpu(ladrf[1]); | |
| 833 | + s->csr[10] = le16_to_cpu(ladrf[2]); | |
| 834 | + s->csr[11] = le16_to_cpu(ladrf[3]); | |
| 835 | + s->csr[12] = le16_to_cpu(padr[0]); | |
| 836 | + s->csr[13] = le16_to_cpu(padr[1]); | |
| 837 | + s->csr[14] = le16_to_cpu(padr[2]); | |
| 766 | 838 | } |
| 767 | - | |
| 768 | -#undef PCNET_INIT | |
| 839 | + s->rdra = PHYSADDR(s, rdra); | |
| 840 | + s->tdra = PHYSADDR(s, tdra); | |
| 769 | 841 | |
| 770 | 842 | CSR_RCVRC(s) = CSR_RCVRL(s); |
| 771 | 843 | CSR_XMTRC(s) = CSR_XMTRL(s); |
| ... | ... | @@ -1035,7 +1107,7 @@ static void pcnet_receive(void *opaque, const uint8_t *buf, int size) |
| 1035 | 1107 | #define PCNET_RECV_STORE() do { \ |
| 1036 | 1108 | int count = MIN(4096 - rmd.rmd1.bcnt,size); \ |
| 1037 | 1109 | target_phys_addr_t rbadr = PHYSADDR(s, rmd.rmd0.rbadr); \ |
| 1038 | - cpu_physical_memory_write(rbadr, src, count); \ | |
| 1110 | + s->phys_mem_write(s->dma_opaque, rbadr, src, count); \ | |
| 1039 | 1111 | src += count; size -= count; \ |
| 1040 | 1112 | rmd.rmd2.mcnt = count; rmd.rmd1.own = 0; \ |
| 1041 | 1113 | RMDSTORE(&rmd, PHYSADDR(s,crda)); \ |
| ... | ... | @@ -1125,14 +1197,14 @@ static void pcnet_transmit(PCNetState *s) |
| 1125 | 1197 | if (tmd.tmd1.stp) { |
| 1126 | 1198 | s->xmit_pos = 0; |
| 1127 | 1199 | if (!tmd.tmd1.enp) { |
| 1128 | - cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr), | |
| 1200 | + s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tmd0.tbadr), | |
| 1129 | 1201 | s->buffer, 4096 - tmd.tmd1.bcnt); |
| 1130 | 1202 | s->xmit_pos += 4096 - tmd.tmd1.bcnt; |
| 1131 | 1203 | } |
| 1132 | 1204 | xmit_cxda = PHYSADDR(s,CSR_CXDA(s)); |
| 1133 | 1205 | } |
| 1134 | 1206 | if (tmd.tmd1.enp && (s->xmit_pos >= 0)) { |
| 1135 | - cpu_physical_memory_read(PHYSADDR(s, tmd.tmd0.tbadr), | |
| 1207 | + s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tmd0.tbadr), | |
| 1136 | 1208 | s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt); |
| 1137 | 1209 | s->xmit_pos += 4096 - tmd.tmd1.bcnt; |
| 1138 | 1210 | #ifdef PCNET_DEBUG |
| ... | ... | @@ -1426,8 +1498,9 @@ static uint32_t pcnet_bcr_readw(PCNetState *s, uint32_t rap) |
| 1426 | 1498 | return val; |
| 1427 | 1499 | } |
| 1428 | 1500 | |
| 1429 | -static void pcnet_h_reset(PCNetState *s) | |
| 1501 | +void pcnet_h_reset(void *opaque) | |
| 1430 | 1502 | { |
| 1503 | + PCNetState *s = opaque; | |
| 1431 | 1504 | int i; |
| 1432 | 1505 | uint16_t checksum; |
| 1433 | 1506 | |
| ... | ... | @@ -1703,6 +1776,90 @@ static uint32_t pcnet_mmio_readl(void *opaque, target_phys_addr_t addr) |
| 1703 | 1776 | } |
| 1704 | 1777 | |
| 1705 | 1778 | |
| 1779 | +static void pcnet_save(QEMUFile *f, void *opaque) | |
| 1780 | +{ | |
| 1781 | + PCNetState *s = opaque; | |
| 1782 | + unsigned int i; | |
| 1783 | + | |
| 1784 | + if (s->pci_dev) | |
| 1785 | + pci_device_save(s->pci_dev, f); | |
| 1786 | + | |
| 1787 | + qemu_put_be32s(f, &s->rap); | |
| 1788 | + qemu_put_be32s(f, &s->isr); | |
| 1789 | + qemu_put_be32s(f, &s->lnkst); | |
| 1790 | + qemu_put_be32s(f, &s->rdra); | |
| 1791 | + qemu_put_be32s(f, &s->tdra); | |
| 1792 | + qemu_put_buffer(f, s->prom, 16); | |
| 1793 | + for (i = 0; i < 128; i++) | |
| 1794 | + qemu_put_be16s(f, &s->csr[i]); | |
| 1795 | + for (i = 0; i < 32; i++) | |
| 1796 | + qemu_put_be16s(f, &s->bcr[i]); | |
| 1797 | + qemu_put_be64s(f, &s->timer); | |
| 1798 | + qemu_put_be32s(f, &s->xmit_pos); | |
| 1799 | + qemu_put_be32s(f, &s->recv_pos); | |
| 1800 | + qemu_put_buffer(f, s->buffer, 4096); | |
| 1801 | + qemu_put_be32s(f, &s->tx_busy); | |
| 1802 | + qemu_put_timer(f, s->poll_timer); | |
| 1803 | +} | |
| 1804 | + | |
| 1805 | +static int pcnet_load(QEMUFile *f, void *opaque, int version_id) | |
| 1806 | +{ | |
| 1807 | + PCNetState *s = opaque; | |
| 1808 | + int i, ret; | |
| 1809 | + | |
| 1810 | + if (version_id != 2) | |
| 1811 | + return -EINVAL; | |
| 1812 | + | |
| 1813 | + if (s->pci_dev) { | |
| 1814 | + ret = pci_device_load(s->pci_dev, f); | |
| 1815 | + if (ret < 0) | |
| 1816 | + return ret; | |
| 1817 | + } | |
| 1818 | + | |
| 1819 | + qemu_get_be32s(f, &s->rap); | |
| 1820 | + qemu_get_be32s(f, &s->isr); | |
| 1821 | + qemu_get_be32s(f, &s->lnkst); | |
| 1822 | + qemu_get_be32s(f, &s->rdra); | |
| 1823 | + qemu_get_be32s(f, &s->tdra); | |
| 1824 | + qemu_get_buffer(f, s->prom, 16); | |
| 1825 | + for (i = 0; i < 128; i++) | |
| 1826 | + qemu_get_be16s(f, &s->csr[i]); | |
| 1827 | + for (i = 0; i < 32; i++) | |
| 1828 | + qemu_get_be16s(f, &s->bcr[i]); | |
| 1829 | + qemu_get_be64s(f, &s->timer); | |
| 1830 | + qemu_get_be32s(f, &s->xmit_pos); | |
| 1831 | + qemu_get_be32s(f, &s->recv_pos); | |
| 1832 | + qemu_get_buffer(f, s->buffer, 4096); | |
| 1833 | + qemu_get_be32s(f, &s->tx_busy); | |
| 1834 | + qemu_get_timer(f, s->poll_timer); | |
| 1835 | + | |
| 1836 | + return 0; | |
| 1837 | +} | |
| 1838 | + | |
| 1839 | +static void pcnet_common_init(PCNetState *d, NICInfo *nd, const char *info_str) | |
| 1840 | +{ | |
| 1841 | + d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d); | |
| 1842 | + | |
| 1843 | + d->nd = nd; | |
| 1844 | + | |
| 1845 | + d->vc = qemu_new_vlan_client(nd->vlan, pcnet_receive, | |
| 1846 | + pcnet_can_receive, d); | |
| 1847 | + | |
| 1848 | + snprintf(d->vc->info_str, sizeof(d->vc->info_str), | |
| 1849 | + "pcnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x", | |
| 1850 | + d->nd->macaddr[0], | |
| 1851 | + d->nd->macaddr[1], | |
| 1852 | + d->nd->macaddr[2], | |
| 1853 | + d->nd->macaddr[3], | |
| 1854 | + d->nd->macaddr[4], | |
| 1855 | + d->nd->macaddr[5]); | |
| 1856 | + | |
| 1857 | + pcnet_h_reset(d); | |
| 1858 | + register_savevm("pcnet", 0, 2, pcnet_save, pcnet_load, d); | |
| 1859 | +} | |
| 1860 | + | |
| 1861 | +/* PCI interface */ | |
| 1862 | + | |
| 1706 | 1863 | static CPUWriteMemoryFunc *pcnet_mmio_write[] = { |
| 1707 | 1864 | (CPUWriteMemoryFunc *)&pcnet_mmio_writeb, |
| 1708 | 1865 | (CPUWriteMemoryFunc *)&pcnet_mmio_writew, |
| ... | ... | @@ -1724,7 +1881,26 @@ static void pcnet_mmio_map(PCIDevice *pci_dev, int region_num, |
| 1724 | 1881 | printf("pcnet_ioport_map addr=0x%08x 0x%08x\n", addr, size); |
| 1725 | 1882 | #endif |
| 1726 | 1883 | |
| 1727 | - cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_io_addr); | |
| 1884 | + cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_index); | |
| 1885 | +} | |
| 1886 | + | |
| 1887 | +static void pcnet_pci_set_irq_cb(void *opaque, int isr) | |
| 1888 | +{ | |
| 1889 | + PCNetState *s = opaque; | |
| 1890 | + | |
| 1891 | + pci_set_irq(&s->dev, 0, isr); | |
| 1892 | +} | |
| 1893 | + | |
| 1894 | +static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr, | |
| 1895 | + uint8_t *buf, int len) | |
| 1896 | +{ | |
| 1897 | + cpu_physical_memory_write(addr, buf, len); | |
| 1898 | +} | |
| 1899 | + | |
| 1900 | +static void pci_physical_memory_read(void *dma_opaque, target_phys_addr_t addr, | |
| 1901 | + uint8_t *buf, int len) | |
| 1902 | +{ | |
| 1903 | + cpu_physical_memory_read(addr, buf, len); | |
| 1728 | 1904 | } |
| 1729 | 1905 | |
| 1730 | 1906 | void pci_pcnet_init(PCIBus *bus, NICInfo *nd) |
| ... | ... | @@ -1760,7 +1936,7 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd) |
| 1760 | 1936 | pci_conf[0x3f] = 0xff; |
| 1761 | 1937 | |
| 1762 | 1938 | /* Handler for memory-mapped I/O */ |
| 1763 | - d->mmio_io_addr = | |
| 1939 | + d->mmio_index = | |
| 1764 | 1940 | cpu_register_io_memory(0, pcnet_mmio_read, pcnet_mmio_write, d); |
| 1765 | 1941 | |
| 1766 | 1942 | pci_register_io_region((PCIDevice *)d, 0, PCNET_IOPORT_SIZE, |
| ... | ... | @@ -1769,21 +1945,58 @@ void pci_pcnet_init(PCIBus *bus, NICInfo *nd) |
| 1769 | 1945 | pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE, |
| 1770 | 1946 | PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map); |
| 1771 | 1947 | |
| 1772 | - d->poll_timer = qemu_new_timer(vm_clock, pcnet_poll_timer, d); | |
| 1948 | + d->set_irq_cb = pcnet_pci_set_irq_cb; | |
| 1949 | + d->phys_mem_read = pci_physical_memory_read; | |
| 1950 | + d->phys_mem_write = pci_physical_memory_write; | |
| 1951 | + d->pci_dev = &d->dev; | |
| 1773 | 1952 | |
| 1774 | - d->nd = nd; | |
| 1953 | + pcnet_common_init(d, nd, "pcnet"); | |
| 1954 | +} | |
| 1775 | 1955 | |
| 1776 | - d->vc = qemu_new_vlan_client(nd->vlan, pcnet_receive, | |
| 1777 | - pcnet_can_receive, d); | |
| 1778 | - | |
| 1779 | - snprintf(d->vc->info_str, sizeof(d->vc->info_str), | |
| 1780 | - "pcnet macaddr=%02x:%02x:%02x:%02x:%02x:%02x", | |
| 1781 | - d->nd->macaddr[0], | |
| 1782 | - d->nd->macaddr[1], | |
| 1783 | - d->nd->macaddr[2], | |
| 1784 | - d->nd->macaddr[3], | |
| 1785 | - d->nd->macaddr[4], | |
| 1786 | - d->nd->macaddr[5]); | |
| 1956 | +/* SPARC32 interface */ | |
| 1787 | 1957 | |
| 1788 | - pcnet_h_reset(d); | |
| 1958 | +#if defined (TARGET_SPARC) && !defined(TARGET_SPARC64) // Avoid compile failure | |
| 1959 | + | |
| 1960 | +static CPUReadMemoryFunc *lance_mem_read[3] = { | |
| 1961 | + (CPUReadMemoryFunc *)&pcnet_ioport_readw, | |
| 1962 | + (CPUReadMemoryFunc *)&pcnet_ioport_readw, | |
| 1963 | + (CPUReadMemoryFunc *)&pcnet_ioport_readw, | |
| 1964 | +}; | |
| 1965 | + | |
| 1966 | +static CPUWriteMemoryFunc *lance_mem_write[3] = { | |
| 1967 | + (CPUWriteMemoryFunc *)&pcnet_ioport_writew, | |
| 1968 | + (CPUWriteMemoryFunc *)&pcnet_ioport_writew, | |
| 1969 | + (CPUWriteMemoryFunc *)&pcnet_ioport_writew, | |
| 1970 | +}; | |
| 1971 | + | |
| 1972 | +static void pcnet_sparc_set_irq_cb(void *opaque, int isr) | |
| 1973 | +{ | |
| 1974 | + PCNetState *s = opaque; | |
| 1975 | + | |
| 1976 | + ledma_set_irq(s->dma_opaque, isr); | |
| 1977 | +} | |
| 1978 | + | |
| 1979 | +void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque) | |
| 1980 | +{ | |
| 1981 | + PCNetState *d; | |
| 1982 | + int lance_io_memory; | |
| 1983 | + | |
| 1984 | + d = qemu_mallocz(sizeof(PCNetState)); | |
| 1985 | + if (!d) | |
| 1986 | + return NULL; | |
| 1987 | + | |
| 1988 | + lance_io_memory = | |
| 1989 | + cpu_register_io_memory(0, lance_mem_read, lance_mem_write, d); | |
| 1990 | + | |
| 1991 | + d->dma_opaque = dma_opaque; | |
| 1992 | + cpu_register_physical_memory(leaddr, 4, lance_io_memory); | |
| 1993 | + | |
| 1994 | + d->set_irq_cb = pcnet_sparc_set_irq_cb; | |
| 1995 | + d->phys_mem_read = ledma_memory_read; | |
| 1996 | + d->phys_mem_write = ledma_memory_write; | |
| 1997 | + | |
| 1998 | + pcnet_common_init(d, nd, "lance"); | |
| 1999 | + | |
| 2000 | + return d; | |
| 1789 | 2001 | } |
| 2002 | +#endif /* TARGET_SPARC */ | ... | ... |