mipsnet.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. #include "hw.h"
  2. #include "mips.h"
  3. #include "net.h"
  4. #include "isa.h"
  5. //#define DEBUG_MIPSNET_SEND
  6. //#define DEBUG_MIPSNET_RECEIVE
  7. //#define DEBUG_MIPSNET_DATA
  8. //#define DEBUG_MIPSNET_IRQ
  9. /* MIPSnet register offsets */
  10. #define MIPSNET_DEV_ID 0x00
  11. #define MIPSNET_BUSY 0x08
  12. #define MIPSNET_RX_DATA_COUNT 0x0c
  13. #define MIPSNET_TX_DATA_COUNT 0x10
  14. #define MIPSNET_INT_CTL 0x14
  15. # define MIPSNET_INTCTL_TXDONE 0x00000001
  16. # define MIPSNET_INTCTL_RXDONE 0x00000002
  17. # define MIPSNET_INTCTL_TESTBIT 0x80000000
  18. #define MIPSNET_INTERRUPT_INFO 0x18
  19. #define MIPSNET_RX_DATA_BUFFER 0x1c
  20. #define MIPSNET_TX_DATA_BUFFER 0x20
  21. #define MAX_ETH_FRAME_SIZE 1514
  22. typedef struct MIPSnetState {
  23. uint32_t busy;
  24. uint32_t rx_count;
  25. uint32_t rx_read;
  26. uint32_t tx_count;
  27. uint32_t tx_written;
  28. uint32_t intctl;
  29. uint8_t rx_buffer[MAX_ETH_FRAME_SIZE];
  30. uint8_t tx_buffer[MAX_ETH_FRAME_SIZE];
  31. int io_base;
  32. qemu_irq irq;
  33. VLANClientState *vc;
  34. } MIPSnetState;
  35. static void mipsnet_reset(MIPSnetState *s)
  36. {
  37. s->busy = 1;
  38. s->rx_count = 0;
  39. s->rx_read = 0;
  40. s->tx_count = 0;
  41. s->tx_written = 0;
  42. s->intctl = 0;
  43. memset(s->rx_buffer, 0, MAX_ETH_FRAME_SIZE);
  44. memset(s->tx_buffer, 0, MAX_ETH_FRAME_SIZE);
  45. }
  46. static void mipsnet_update_irq(MIPSnetState *s)
  47. {
  48. int isr = !!s->intctl;
  49. #ifdef DEBUG_MIPSNET_IRQ
  50. printf("mipsnet: Set IRQ to %d (%02x)\n", isr, s->intctl);
  51. #endif
  52. qemu_set_irq(s->irq, isr);
  53. }
  54. static int mipsnet_buffer_full(MIPSnetState *s)
  55. {
  56. if (s->rx_count >= MAX_ETH_FRAME_SIZE)
  57. return 1;
  58. return 0;
  59. }
  60. static int mipsnet_can_receive(void *opaque)
  61. {
  62. MIPSnetState *s = opaque;
  63. if (s->busy)
  64. return 0;
  65. return !mipsnet_buffer_full(s);
  66. }
  67. static void mipsnet_receive(void *opaque, const uint8_t *buf, int size)
  68. {
  69. MIPSnetState *s = opaque;
  70. #ifdef DEBUG_MIPSNET_RECEIVE
  71. printf("mipsnet: receiving len=%d\n", size);
  72. #endif
  73. if (!mipsnet_can_receive(opaque))
  74. return;
  75. s->busy = 1;
  76. /* Just accept everything. */
  77. /* Write packet data. */
  78. memcpy(s->rx_buffer, buf, size);
  79. s->rx_count = size;
  80. s->rx_read = 0;
  81. /* Now we can signal we have received something. */
  82. s->intctl |= MIPSNET_INTCTL_RXDONE;
  83. mipsnet_update_irq(s);
  84. }
  85. static uint32_t mipsnet_ioport_read(void *opaque, uint32_t addr)
  86. {
  87. MIPSnetState *s = opaque;
  88. int ret = 0;
  89. addr &= 0x3f;
  90. switch (addr) {
  91. case MIPSNET_DEV_ID:
  92. ret = be32_to_cpu(0x4d495053); /* MIPS */
  93. break;
  94. case MIPSNET_DEV_ID + 4:
  95. ret = be32_to_cpu(0x4e455430); /* NET0 */
  96. break;
  97. case MIPSNET_BUSY:
  98. ret = s->busy;
  99. break;
  100. case MIPSNET_RX_DATA_COUNT:
  101. ret = s->rx_count;
  102. break;
  103. case MIPSNET_TX_DATA_COUNT:
  104. ret = s->tx_count;
  105. break;
  106. case MIPSNET_INT_CTL:
  107. ret = s->intctl;
  108. s->intctl &= ~MIPSNET_INTCTL_TESTBIT;
  109. break;
  110. case MIPSNET_INTERRUPT_INFO:
  111. /* XXX: This seems to be a per-VPE interrupt number. */
  112. ret = 0;
  113. break;
  114. case MIPSNET_RX_DATA_BUFFER:
  115. if (s->rx_count) {
  116. s->rx_count--;
  117. ret = s->rx_buffer[s->rx_read++];
  118. }
  119. break;
  120. /* Reads as zero. */
  121. case MIPSNET_TX_DATA_BUFFER:
  122. default:
  123. break;
  124. }
  125. #ifdef DEBUG_MIPSNET_DATA
  126. printf("mipsnet: read addr=0x%02x val=0x%02x\n", addr, ret);
  127. #endif
  128. return ret;
  129. }
  130. static void mipsnet_ioport_write(void *opaque, uint32_t addr, uint32_t val)
  131. {
  132. MIPSnetState *s = opaque;
  133. addr &= 0x3f;
  134. #ifdef DEBUG_MIPSNET_DATA
  135. printf("mipsnet: write addr=0x%02x val=0x%02x\n", addr, val);
  136. #endif
  137. switch (addr) {
  138. case MIPSNET_TX_DATA_COUNT:
  139. s->tx_count = (val <= MAX_ETH_FRAME_SIZE) ? val : 0;
  140. s->tx_written = 0;
  141. break;
  142. case MIPSNET_INT_CTL:
  143. if (val & MIPSNET_INTCTL_TXDONE) {
  144. s->intctl &= ~MIPSNET_INTCTL_TXDONE;
  145. } else if (val & MIPSNET_INTCTL_RXDONE) {
  146. s->intctl &= ~MIPSNET_INTCTL_RXDONE;
  147. } else if (val & MIPSNET_INTCTL_TESTBIT) {
  148. mipsnet_reset(s);
  149. s->intctl |= MIPSNET_INTCTL_TESTBIT;
  150. } else if (!val) {
  151. /* ACK testbit interrupt, flag was cleared on read. */
  152. }
  153. s->busy = !!s->intctl;
  154. mipsnet_update_irq(s);
  155. break;
  156. case MIPSNET_TX_DATA_BUFFER:
  157. s->tx_buffer[s->tx_written++] = val;
  158. if (s->tx_written == s->tx_count) {
  159. /* Send buffer. */
  160. #ifdef DEBUG_MIPSNET_SEND
  161. printf("mipsnet: sending len=%d\n", s->tx_count);
  162. #endif
  163. qemu_send_packet(s->vc, s->tx_buffer, s->tx_count);
  164. s->tx_count = s->tx_written = 0;
  165. s->intctl |= MIPSNET_INTCTL_TXDONE;
  166. s->busy = 1;
  167. mipsnet_update_irq(s);
  168. }
  169. break;
  170. /* Read-only registers */
  171. case MIPSNET_DEV_ID:
  172. case MIPSNET_BUSY:
  173. case MIPSNET_RX_DATA_COUNT:
  174. case MIPSNET_INTERRUPT_INFO:
  175. case MIPSNET_RX_DATA_BUFFER:
  176. default:
  177. break;
  178. }
  179. }
  180. static void mipsnet_save(QEMUFile *f, void *opaque)
  181. {
  182. MIPSnetState *s = opaque;
  183. qemu_put_be32s(f, &s->busy);
  184. qemu_put_be32s(f, &s->rx_count);
  185. qemu_put_be32s(f, &s->rx_read);
  186. qemu_put_be32s(f, &s->tx_count);
  187. qemu_put_be32s(f, &s->tx_written);
  188. qemu_put_be32s(f, &s->intctl);
  189. qemu_put_buffer(f, s->rx_buffer, MAX_ETH_FRAME_SIZE);
  190. qemu_put_buffer(f, s->tx_buffer, MAX_ETH_FRAME_SIZE);
  191. }
  192. static int mipsnet_load(QEMUFile *f, void *opaque, int version_id)
  193. {
  194. MIPSnetState *s = opaque;
  195. if (version_id > 0)
  196. return -EINVAL;
  197. qemu_get_be32s(f, &s->busy);
  198. qemu_get_be32s(f, &s->rx_count);
  199. qemu_get_be32s(f, &s->rx_read);
  200. qemu_get_be32s(f, &s->tx_count);
  201. qemu_get_be32s(f, &s->tx_written);
  202. qemu_get_be32s(f, &s->intctl);
  203. qemu_get_buffer(f, s->rx_buffer, MAX_ETH_FRAME_SIZE);
  204. qemu_get_buffer(f, s->tx_buffer, MAX_ETH_FRAME_SIZE);
  205. return 0;
  206. }
  207. static void mipsnet_cleanup(VLANClientState *vc)
  208. {
  209. MIPSnetState *s = vc->opaque;
  210. unregister_savevm("mipsnet", s);
  211. isa_unassign_ioport(s->io_base, 36);
  212. qemu_free(s);
  213. }
  214. void mipsnet_init (int base, qemu_irq irq, NICInfo *nd)
  215. {
  216. MIPSnetState *s;
  217. qemu_check_nic_model(nd, "mipsnet");
  218. s = qemu_mallocz(sizeof(MIPSnetState));
  219. register_ioport_write(base, 36, 1, mipsnet_ioport_write, s);
  220. register_ioport_read(base, 36, 1, mipsnet_ioport_read, s);
  221. register_ioport_write(base, 36, 2, mipsnet_ioport_write, s);
  222. register_ioport_read(base, 36, 2, mipsnet_ioport_read, s);
  223. register_ioport_write(base, 36, 4, mipsnet_ioport_write, s);
  224. register_ioport_read(base, 36, 4, mipsnet_ioport_read, s);
  225. s->io_base = base;
  226. s->irq = irq;
  227. if (nd && nd->vlan) {
  228. s->vc = nd->vc = qemu_new_vlan_client(nd->vlan, nd->model, nd->name,
  229. mipsnet_receive,
  230. mipsnet_can_receive,
  231. mipsnet_cleanup, s);
  232. } else {
  233. s->vc = NULL;
  234. }
  235. qemu_format_nic_info_str(s->vc, nd->macaddr);
  236. mipsnet_reset(s);
  237. register_savevm("mipsnet", 0, 0, mipsnet_save, mipsnet_load, s);
  238. }