dp8393x.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914
  1. /*
  2. * QEMU NS SONIC DP8393x netcard
  3. *
  4. * Copyright (c) 2008-2009 Herve Poussineau
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License as
  8. * published by the Free Software Foundation; either version 2 of
  9. * the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License along
  17. * with this program; if not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include "hw.h"
  20. #include "qemu-timer.h"
  21. #include "net.h"
  22. #include "mips.h"
  23. //#define DEBUG_SONIC
  24. /* Calculate CRCs properly on Rx packets */
  25. #define SONIC_CALCULATE_RXCRC
  26. #if defined(SONIC_CALCULATE_RXCRC)
  27. /* For crc32 */
  28. #include <zlib.h>
  29. #endif
  30. #ifdef DEBUG_SONIC
  31. #define DPRINTF(fmt, ...) \
  32. do { printf("sonic: " fmt , ## __VA_ARGS__); } while (0)
  33. static const char* reg_names[] = {
  34. "CR", "DCR", "RCR", "TCR", "IMR", "ISR", "UTDA", "CTDA",
  35. "TPS", "TFC", "TSA0", "TSA1", "TFS", "URDA", "CRDA", "CRBA0",
  36. "CRBA1", "RBWC0", "RBWC1", "EOBC", "URRA", "RSA", "REA", "RRP",
  37. "RWP", "TRBA0", "TRBA1", "0x1b", "0x1c", "0x1d", "0x1e", "LLFA",
  38. "TTDA", "CEP", "CAP2", "CAP1", "CAP0", "CE", "CDP", "CDC",
  39. "SR", "WT0", "WT1", "RSC", "CRCT", "FAET", "MPT", "MDT",
  40. "0x30", "0x31", "0x32", "0x33", "0x34", "0x35", "0x36", "0x37",
  41. "0x38", "0x39", "0x3a", "0x3b", "0x3c", "0x3d", "0x3e", "DCR2" };
  42. #else
  43. #define DPRINTF(fmt, ...) do {} while (0)
  44. #endif
  45. #define SONIC_ERROR(fmt, ...) \
  46. do { printf("sonic ERROR: %s: " fmt, __func__ , ## __VA_ARGS__); } while (0)
  47. #define SONIC_CR 0x00
  48. #define SONIC_DCR 0x01
  49. #define SONIC_RCR 0x02
  50. #define SONIC_TCR 0x03
  51. #define SONIC_IMR 0x04
  52. #define SONIC_ISR 0x05
  53. #define SONIC_UTDA 0x06
  54. #define SONIC_CTDA 0x07
  55. #define SONIC_TPS 0x08
  56. #define SONIC_TFC 0x09
  57. #define SONIC_TSA0 0x0a
  58. #define SONIC_TSA1 0x0b
  59. #define SONIC_TFS 0x0c
  60. #define SONIC_URDA 0x0d
  61. #define SONIC_CRDA 0x0e
  62. #define SONIC_CRBA0 0x0f
  63. #define SONIC_CRBA1 0x10
  64. #define SONIC_RBWC0 0x11
  65. #define SONIC_RBWC1 0x12
  66. #define SONIC_EOBC 0x13
  67. #define SONIC_URRA 0x14
  68. #define SONIC_RSA 0x15
  69. #define SONIC_REA 0x16
  70. #define SONIC_RRP 0x17
  71. #define SONIC_RWP 0x18
  72. #define SONIC_TRBA0 0x19
  73. #define SONIC_TRBA1 0x1a
  74. #define SONIC_LLFA 0x1f
  75. #define SONIC_TTDA 0x20
  76. #define SONIC_CEP 0x21
  77. #define SONIC_CAP2 0x22
  78. #define SONIC_CAP1 0x23
  79. #define SONIC_CAP0 0x24
  80. #define SONIC_CE 0x25
  81. #define SONIC_CDP 0x26
  82. #define SONIC_CDC 0x27
  83. #define SONIC_SR 0x28
  84. #define SONIC_WT0 0x29
  85. #define SONIC_WT1 0x2a
  86. #define SONIC_RSC 0x2b
  87. #define SONIC_CRCT 0x2c
  88. #define SONIC_FAET 0x2d
  89. #define SONIC_MPT 0x2e
  90. #define SONIC_MDT 0x2f
  91. #define SONIC_DCR2 0x3f
  92. #define SONIC_CR_HTX 0x0001
  93. #define SONIC_CR_TXP 0x0002
  94. #define SONIC_CR_RXDIS 0x0004
  95. #define SONIC_CR_RXEN 0x0008
  96. #define SONIC_CR_STP 0x0010
  97. #define SONIC_CR_ST 0x0020
  98. #define SONIC_CR_RST 0x0080
  99. #define SONIC_CR_RRRA 0x0100
  100. #define SONIC_CR_LCAM 0x0200
  101. #define SONIC_CR_MASK 0x03bf
  102. #define SONIC_DCR_DW 0x0020
  103. #define SONIC_DCR_LBR 0x2000
  104. #define SONIC_DCR_EXBUS 0x8000
  105. #define SONIC_RCR_PRX 0x0001
  106. #define SONIC_RCR_LBK 0x0002
  107. #define SONIC_RCR_FAER 0x0004
  108. #define SONIC_RCR_CRCR 0x0008
  109. #define SONIC_RCR_CRS 0x0020
  110. #define SONIC_RCR_LPKT 0x0040
  111. #define SONIC_RCR_BC 0x0080
  112. #define SONIC_RCR_MC 0x0100
  113. #define SONIC_RCR_LB0 0x0200
  114. #define SONIC_RCR_LB1 0x0400
  115. #define SONIC_RCR_AMC 0x0800
  116. #define SONIC_RCR_PRO 0x1000
  117. #define SONIC_RCR_BRD 0x2000
  118. #define SONIC_RCR_RNT 0x4000
  119. #define SONIC_TCR_PTX 0x0001
  120. #define SONIC_TCR_BCM 0x0002
  121. #define SONIC_TCR_FU 0x0004
  122. #define SONIC_TCR_EXC 0x0040
  123. #define SONIC_TCR_CRSL 0x0080
  124. #define SONIC_TCR_NCRS 0x0100
  125. #define SONIC_TCR_EXD 0x0400
  126. #define SONIC_TCR_CRCI 0x2000
  127. #define SONIC_TCR_PINT 0x8000
  128. #define SONIC_ISR_RBE 0x0020
  129. #define SONIC_ISR_RDE 0x0040
  130. #define SONIC_ISR_TC 0x0080
  131. #define SONIC_ISR_TXDN 0x0200
  132. #define SONIC_ISR_PKTRX 0x0400
  133. #define SONIC_ISR_PINT 0x0800
  134. #define SONIC_ISR_LCD 0x1000
  135. typedef struct dp8393xState {
  136. /* Hardware */
  137. int it_shift;
  138. qemu_irq irq;
  139. #ifdef DEBUG_SONIC
  140. int irq_level;
  141. #endif
  142. QEMUTimer *watchdog;
  143. int64_t wt_last_update;
  144. NICConf conf;
  145. NICState *nic;
  146. int mmio_index;
  147. /* Registers */
  148. uint8_t cam[16][6];
  149. uint16_t regs[0x40];
  150. /* Temporaries */
  151. uint8_t tx_buffer[0x10000];
  152. int loopback_packet;
  153. /* Memory access */
  154. void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write);
  155. void* mem_opaque;
  156. } dp8393xState;
  157. static void dp8393x_update_irq(dp8393xState *s)
  158. {
  159. int level = (s->regs[SONIC_IMR] & s->regs[SONIC_ISR]) ? 1 : 0;
  160. #ifdef DEBUG_SONIC
  161. if (level != s->irq_level) {
  162. s->irq_level = level;
  163. if (level) {
  164. DPRINTF("raise irq, isr is 0x%04x\n", s->regs[SONIC_ISR]);
  165. } else {
  166. DPRINTF("lower irq\n");
  167. }
  168. }
  169. #endif
  170. qemu_set_irq(s->irq, level);
  171. }
  172. static void do_load_cam(dp8393xState *s)
  173. {
  174. uint16_t data[8];
  175. int width, size;
  176. uint16_t index = 0;
  177. width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
  178. size = sizeof(uint16_t) * 4 * width;
  179. while (s->regs[SONIC_CDC] & 0x1f) {
  180. /* Fill current entry */
  181. s->memory_rw(s->mem_opaque,
  182. (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
  183. (uint8_t *)data, size, 0);
  184. s->cam[index][0] = data[1 * width] & 0xff;
  185. s->cam[index][1] = data[1 * width] >> 8;
  186. s->cam[index][2] = data[2 * width] & 0xff;
  187. s->cam[index][3] = data[2 * width] >> 8;
  188. s->cam[index][4] = data[3 * width] & 0xff;
  189. s->cam[index][5] = data[3 * width] >> 8;
  190. DPRINTF("load cam[%d] with %02x%02x%02x%02x%02x%02x\n", index,
  191. s->cam[index][0], s->cam[index][1], s->cam[index][2],
  192. s->cam[index][3], s->cam[index][4], s->cam[index][5]);
  193. /* Move to next entry */
  194. s->regs[SONIC_CDC]--;
  195. s->regs[SONIC_CDP] += size;
  196. index++;
  197. }
  198. /* Read CAM enable */
  199. s->memory_rw(s->mem_opaque,
  200. (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_CDP],
  201. (uint8_t *)data, size, 0);
  202. s->regs[SONIC_CE] = data[0 * width];
  203. DPRINTF("load cam done. cam enable mask 0x%04x\n", s->regs[SONIC_CE]);
  204. /* Done */
  205. s->regs[SONIC_CR] &= ~SONIC_CR_LCAM;
  206. s->regs[SONIC_ISR] |= SONIC_ISR_LCD;
  207. dp8393x_update_irq(s);
  208. }
  209. static void do_read_rra(dp8393xState *s)
  210. {
  211. uint16_t data[8];
  212. int width, size;
  213. /* Read memory */
  214. width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
  215. size = sizeof(uint16_t) * 4 * width;
  216. s->memory_rw(s->mem_opaque,
  217. (s->regs[SONIC_URRA] << 16) | s->regs[SONIC_RRP],
  218. (uint8_t *)data, size, 0);
  219. /* Update SONIC registers */
  220. s->regs[SONIC_CRBA0] = data[0 * width];
  221. s->regs[SONIC_CRBA1] = data[1 * width];
  222. s->regs[SONIC_RBWC0] = data[2 * width];
  223. s->regs[SONIC_RBWC1] = data[3 * width];
  224. DPRINTF("CRBA0/1: 0x%04x/0x%04x, RBWC0/1: 0x%04x/0x%04x\n",
  225. s->regs[SONIC_CRBA0], s->regs[SONIC_CRBA1],
  226. s->regs[SONIC_RBWC0], s->regs[SONIC_RBWC1]);
  227. /* Go to next entry */
  228. s->regs[SONIC_RRP] += size;
  229. /* Handle wrap */
  230. if (s->regs[SONIC_RRP] == s->regs[SONIC_REA]) {
  231. s->regs[SONIC_RRP] = s->regs[SONIC_RSA];
  232. }
  233. /* Check resource exhaustion */
  234. if (s->regs[SONIC_RRP] == s->regs[SONIC_RWP])
  235. {
  236. s->regs[SONIC_ISR] |= SONIC_ISR_RBE;
  237. dp8393x_update_irq(s);
  238. }
  239. /* Done */
  240. s->regs[SONIC_CR] &= ~SONIC_CR_RRRA;
  241. }
  242. static void do_software_reset(dp8393xState *s)
  243. {
  244. qemu_del_timer(s->watchdog);
  245. s->regs[SONIC_CR] &= ~(SONIC_CR_LCAM | SONIC_CR_RRRA | SONIC_CR_TXP | SONIC_CR_HTX);
  246. s->regs[SONIC_CR] |= SONIC_CR_RST | SONIC_CR_RXDIS;
  247. }
  248. static void set_next_tick(dp8393xState *s)
  249. {
  250. uint32_t ticks;
  251. int64_t delay;
  252. if (s->regs[SONIC_CR] & SONIC_CR_STP) {
  253. qemu_del_timer(s->watchdog);
  254. return;
  255. }
  256. ticks = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
  257. s->wt_last_update = qemu_get_clock_ns(vm_clock);
  258. delay = get_ticks_per_sec() * ticks / 5000000;
  259. qemu_mod_timer(s->watchdog, s->wt_last_update + delay);
  260. }
  261. static void update_wt_regs(dp8393xState *s)
  262. {
  263. int64_t elapsed;
  264. uint32_t val;
  265. if (s->regs[SONIC_CR] & SONIC_CR_STP) {
  266. qemu_del_timer(s->watchdog);
  267. return;
  268. }
  269. elapsed = s->wt_last_update - qemu_get_clock_ns(vm_clock);
  270. val = s->regs[SONIC_WT1] << 16 | s->regs[SONIC_WT0];
  271. val -= elapsed / 5000000;
  272. s->regs[SONIC_WT1] = (val >> 16) & 0xffff;
  273. s->regs[SONIC_WT0] = (val >> 0) & 0xffff;
  274. set_next_tick(s);
  275. }
  276. static void do_start_timer(dp8393xState *s)
  277. {
  278. s->regs[SONIC_CR] &= ~SONIC_CR_STP;
  279. set_next_tick(s);
  280. }
  281. static void do_stop_timer(dp8393xState *s)
  282. {
  283. s->regs[SONIC_CR] &= ~SONIC_CR_ST;
  284. update_wt_regs(s);
  285. }
  286. static void do_receiver_enable(dp8393xState *s)
  287. {
  288. s->regs[SONIC_CR] &= ~SONIC_CR_RXDIS;
  289. }
  290. static void do_receiver_disable(dp8393xState *s)
  291. {
  292. s->regs[SONIC_CR] &= ~SONIC_CR_RXEN;
  293. }
  294. static void do_transmit_packets(dp8393xState *s)
  295. {
  296. uint16_t data[12];
  297. int width, size;
  298. int tx_len, len;
  299. uint16_t i;
  300. width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
  301. while (1) {
  302. /* Read memory */
  303. DPRINTF("Transmit packet at %08x\n",
  304. (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_CTDA]);
  305. size = sizeof(uint16_t) * 6 * width;
  306. s->regs[SONIC_TTDA] = s->regs[SONIC_CTDA];
  307. s->memory_rw(s->mem_opaque,
  308. ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * width,
  309. (uint8_t *)data, size, 0);
  310. tx_len = 0;
  311. /* Update registers */
  312. s->regs[SONIC_TCR] = data[0 * width] & 0xf000;
  313. s->regs[SONIC_TPS] = data[1 * width];
  314. s->regs[SONIC_TFC] = data[2 * width];
  315. s->regs[SONIC_TSA0] = data[3 * width];
  316. s->regs[SONIC_TSA1] = data[4 * width];
  317. s->regs[SONIC_TFS] = data[5 * width];
  318. /* Handle programmable interrupt */
  319. if (s->regs[SONIC_TCR] & SONIC_TCR_PINT) {
  320. s->regs[SONIC_ISR] |= SONIC_ISR_PINT;
  321. } else {
  322. s->regs[SONIC_ISR] &= ~SONIC_ISR_PINT;
  323. }
  324. for (i = 0; i < s->regs[SONIC_TFC]; ) {
  325. /* Append fragment */
  326. len = s->regs[SONIC_TFS];
  327. if (tx_len + len > sizeof(s->tx_buffer)) {
  328. len = sizeof(s->tx_buffer) - tx_len;
  329. }
  330. s->memory_rw(s->mem_opaque,
  331. (s->regs[SONIC_TSA1] << 16) | s->regs[SONIC_TSA0],
  332. &s->tx_buffer[tx_len], len, 0);
  333. tx_len += len;
  334. i++;
  335. if (i != s->regs[SONIC_TFC]) {
  336. /* Read next fragment details */
  337. size = sizeof(uint16_t) * 3 * width;
  338. s->memory_rw(s->mem_opaque,
  339. ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * i) * width,
  340. (uint8_t *)data, size, 0);
  341. s->regs[SONIC_TSA0] = data[0 * width];
  342. s->regs[SONIC_TSA1] = data[1 * width];
  343. s->regs[SONIC_TFS] = data[2 * width];
  344. }
  345. }
  346. /* Handle Ethernet checksum */
  347. if (!(s->regs[SONIC_TCR] & SONIC_TCR_CRCI)) {
  348. /* Don't append FCS there, to look like slirp packets
  349. * which don't have one */
  350. } else {
  351. /* Remove existing FCS */
  352. tx_len -= 4;
  353. }
  354. if (s->regs[SONIC_RCR] & (SONIC_RCR_LB1 | SONIC_RCR_LB0)) {
  355. /* Loopback */
  356. s->regs[SONIC_TCR] |= SONIC_TCR_CRSL;
  357. if (s->nic->nc.info->can_receive(&s->nic->nc)) {
  358. s->loopback_packet = 1;
  359. s->nic->nc.info->receive(&s->nic->nc, s->tx_buffer, tx_len);
  360. }
  361. } else {
  362. /* Transmit packet */
  363. qemu_send_packet(&s->nic->nc, s->tx_buffer, tx_len);
  364. }
  365. s->regs[SONIC_TCR] |= SONIC_TCR_PTX;
  366. /* Write status */
  367. data[0 * width] = s->regs[SONIC_TCR] & 0x0fff; /* status */
  368. size = sizeof(uint16_t) * width;
  369. s->memory_rw(s->mem_opaque,
  370. (s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA],
  371. (uint8_t *)data, size, 1);
  372. if (!(s->regs[SONIC_CR] & SONIC_CR_HTX)) {
  373. /* Read footer of packet */
  374. size = sizeof(uint16_t) * width;
  375. s->memory_rw(s->mem_opaque,
  376. ((s->regs[SONIC_UTDA] << 16) | s->regs[SONIC_TTDA]) + sizeof(uint16_t) * (4 + 3 * s->regs[SONIC_TFC]) * width,
  377. (uint8_t *)data, size, 0);
  378. s->regs[SONIC_CTDA] = data[0 * width] & ~0x1;
  379. if (data[0 * width] & 0x1) {
  380. /* EOL detected */
  381. break;
  382. }
  383. }
  384. }
  385. /* Done */
  386. s->regs[SONIC_CR] &= ~SONIC_CR_TXP;
  387. s->regs[SONIC_ISR] |= SONIC_ISR_TXDN;
  388. dp8393x_update_irq(s);
  389. }
  390. static void do_halt_transmission(dp8393xState *s)
  391. {
  392. /* Nothing to do */
  393. }
  394. static void do_command(dp8393xState *s, uint16_t command)
  395. {
  396. if ((s->regs[SONIC_CR] & SONIC_CR_RST) && !(command & SONIC_CR_RST)) {
  397. s->regs[SONIC_CR] &= ~SONIC_CR_RST;
  398. return;
  399. }
  400. s->regs[SONIC_CR] |= (command & SONIC_CR_MASK);
  401. if (command & SONIC_CR_HTX)
  402. do_halt_transmission(s);
  403. if (command & SONIC_CR_TXP)
  404. do_transmit_packets(s);
  405. if (command & SONIC_CR_RXDIS)
  406. do_receiver_disable(s);
  407. if (command & SONIC_CR_RXEN)
  408. do_receiver_enable(s);
  409. if (command & SONIC_CR_STP)
  410. do_stop_timer(s);
  411. if (command & SONIC_CR_ST)
  412. do_start_timer(s);
  413. if (command & SONIC_CR_RST)
  414. do_software_reset(s);
  415. if (command & SONIC_CR_RRRA)
  416. do_read_rra(s);
  417. if (command & SONIC_CR_LCAM)
  418. do_load_cam(s);
  419. }
  420. static uint16_t read_register(dp8393xState *s, int reg)
  421. {
  422. uint16_t val = 0;
  423. switch (reg) {
  424. /* Update data before reading it */
  425. case SONIC_WT0:
  426. case SONIC_WT1:
  427. update_wt_regs(s);
  428. val = s->regs[reg];
  429. break;
  430. /* Accept read to some registers only when in reset mode */
  431. case SONIC_CAP2:
  432. case SONIC_CAP1:
  433. case SONIC_CAP0:
  434. if (s->regs[SONIC_CR] & SONIC_CR_RST) {
  435. val = s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg) + 1] << 8;
  436. val |= s->cam[s->regs[SONIC_CEP] & 0xf][2* (SONIC_CAP0 - reg)];
  437. }
  438. break;
  439. /* All other registers have no special contrainst */
  440. default:
  441. val = s->regs[reg];
  442. }
  443. DPRINTF("read 0x%04x from reg %s\n", val, reg_names[reg]);
  444. return val;
  445. }
  446. static void write_register(dp8393xState *s, int reg, uint16_t val)
  447. {
  448. DPRINTF("write 0x%04x to reg %s\n", val, reg_names[reg]);
  449. switch (reg) {
  450. /* Command register */
  451. case SONIC_CR:
  452. do_command(s, val);;
  453. break;
  454. /* Prevent write to read-only registers */
  455. case SONIC_CAP2:
  456. case SONIC_CAP1:
  457. case SONIC_CAP0:
  458. case SONIC_SR:
  459. case SONIC_MDT:
  460. DPRINTF("writing to reg %d invalid\n", reg);
  461. break;
  462. /* Accept write to some registers only when in reset mode */
  463. case SONIC_DCR:
  464. if (s->regs[SONIC_CR] & SONIC_CR_RST) {
  465. s->regs[reg] = val & 0xbfff;
  466. } else {
  467. DPRINTF("writing to DCR invalid\n");
  468. }
  469. break;
  470. case SONIC_DCR2:
  471. if (s->regs[SONIC_CR] & SONIC_CR_RST) {
  472. s->regs[reg] = val & 0xf017;
  473. } else {
  474. DPRINTF("writing to DCR2 invalid\n");
  475. }
  476. break;
  477. /* 12 lower bytes are Read Only */
  478. case SONIC_TCR:
  479. s->regs[reg] = val & 0xf000;
  480. break;
  481. /* 9 lower bytes are Read Only */
  482. case SONIC_RCR:
  483. s->regs[reg] = val & 0xffe0;
  484. break;
  485. /* Ignore most significant bit */
  486. case SONIC_IMR:
  487. s->regs[reg] = val & 0x7fff;
  488. dp8393x_update_irq(s);
  489. break;
  490. /* Clear bits by writing 1 to them */
  491. case SONIC_ISR:
  492. val &= s->regs[reg];
  493. s->regs[reg] &= ~val;
  494. if (val & SONIC_ISR_RBE) {
  495. do_read_rra(s);
  496. }
  497. dp8393x_update_irq(s);
  498. break;
  499. /* Ignore least significant bit */
  500. case SONIC_RSA:
  501. case SONIC_REA:
  502. case SONIC_RRP:
  503. case SONIC_RWP:
  504. s->regs[reg] = val & 0xfffe;
  505. break;
  506. /* Invert written value for some registers */
  507. case SONIC_CRCT:
  508. case SONIC_FAET:
  509. case SONIC_MPT:
  510. s->regs[reg] = val ^ 0xffff;
  511. break;
  512. /* All other registers have no special contrainst */
  513. default:
  514. s->regs[reg] = val;
  515. }
  516. if (reg == SONIC_WT0 || reg == SONIC_WT1) {
  517. set_next_tick(s);
  518. }
  519. }
  520. static void dp8393x_watchdog(void *opaque)
  521. {
  522. dp8393xState *s = opaque;
  523. if (s->regs[SONIC_CR] & SONIC_CR_STP) {
  524. return;
  525. }
  526. s->regs[SONIC_WT1] = 0xffff;
  527. s->regs[SONIC_WT0] = 0xffff;
  528. set_next_tick(s);
  529. /* Signal underflow */
  530. s->regs[SONIC_ISR] |= SONIC_ISR_TC;
  531. dp8393x_update_irq(s);
  532. }
  533. static uint32_t dp8393x_readw(void *opaque, target_phys_addr_t addr)
  534. {
  535. dp8393xState *s = opaque;
  536. int reg;
  537. if ((addr & ((1 << s->it_shift) - 1)) != 0) {
  538. return 0;
  539. }
  540. reg = addr >> s->it_shift;
  541. return read_register(s, reg);
  542. }
  543. static uint32_t dp8393x_readb(void *opaque, target_phys_addr_t addr)
  544. {
  545. uint16_t v = dp8393x_readw(opaque, addr & ~0x1);
  546. return (v >> (8 * (addr & 0x1))) & 0xff;
  547. }
  548. static uint32_t dp8393x_readl(void *opaque, target_phys_addr_t addr)
  549. {
  550. uint32_t v;
  551. v = dp8393x_readw(opaque, addr);
  552. v |= dp8393x_readw(opaque, addr + 2) << 16;
  553. return v;
  554. }
  555. static void dp8393x_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
  556. {
  557. dp8393xState *s = opaque;
  558. int reg;
  559. if ((addr & ((1 << s->it_shift) - 1)) != 0) {
  560. return;
  561. }
  562. reg = addr >> s->it_shift;
  563. write_register(s, reg, (uint16_t)val);
  564. }
  565. static void dp8393x_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
  566. {
  567. uint16_t old_val = dp8393x_readw(opaque, addr & ~0x1);
  568. switch (addr & 3) {
  569. case 0:
  570. val = val | (old_val & 0xff00);
  571. break;
  572. case 1:
  573. val = (val << 8) | (old_val & 0x00ff);
  574. break;
  575. }
  576. dp8393x_writew(opaque, addr & ~0x1, val);
  577. }
  578. static void dp8393x_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
  579. {
  580. dp8393x_writew(opaque, addr, val & 0xffff);
  581. dp8393x_writew(opaque, addr + 2, (val >> 16) & 0xffff);
  582. }
  583. static CPUReadMemoryFunc * const dp8393x_read[3] = {
  584. dp8393x_readb,
  585. dp8393x_readw,
  586. dp8393x_readl,
  587. };
  588. static CPUWriteMemoryFunc * const dp8393x_write[3] = {
  589. dp8393x_writeb,
  590. dp8393x_writew,
  591. dp8393x_writel,
  592. };
  593. static int nic_can_receive(VLANClientState *nc)
  594. {
  595. dp8393xState *s = DO_UPCAST(NICState, nc, nc)->opaque;
  596. if (!(s->regs[SONIC_CR] & SONIC_CR_RXEN))
  597. return 0;
  598. if (s->regs[SONIC_ISR] & SONIC_ISR_RBE)
  599. return 0;
  600. return 1;
  601. }
  602. static int receive_filter(dp8393xState *s, const uint8_t * buf, int size)
  603. {
  604. static const uint8_t bcast[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
  605. int i;
  606. /* Check for runt packet (remember that checksum is not there) */
  607. if (size < 64 - 4) {
  608. return (s->regs[SONIC_RCR] & SONIC_RCR_RNT) ? 0 : -1;
  609. }
  610. /* Check promiscuous mode */
  611. if ((s->regs[SONIC_RCR] & SONIC_RCR_PRO) && (buf[0] & 1) == 0) {
  612. return 0;
  613. }
  614. /* Check multicast packets */
  615. if ((s->regs[SONIC_RCR] & SONIC_RCR_AMC) && (buf[0] & 1) == 1) {
  616. return SONIC_RCR_MC;
  617. }
  618. /* Check broadcast */
  619. if ((s->regs[SONIC_RCR] & SONIC_RCR_BRD) && !memcmp(buf, bcast, sizeof(bcast))) {
  620. return SONIC_RCR_BC;
  621. }
  622. /* Check CAM */
  623. for (i = 0; i < 16; i++) {
  624. if (s->regs[SONIC_CE] & (1 << i)) {
  625. /* Entry enabled */
  626. if (!memcmp(buf, s->cam[i], sizeof(s->cam[i]))) {
  627. return 0;
  628. }
  629. }
  630. }
  631. return -1;
  632. }
  633. static ssize_t nic_receive(VLANClientState *nc, const uint8_t * buf, size_t size)
  634. {
  635. dp8393xState *s = DO_UPCAST(NICState, nc, nc)->opaque;
  636. uint16_t data[10];
  637. int packet_type;
  638. uint32_t available, address;
  639. int width, rx_len = size;
  640. uint32_t checksum;
  641. width = (s->regs[SONIC_DCR] & SONIC_DCR_DW) ? 2 : 1;
  642. s->regs[SONIC_RCR] &= ~(SONIC_RCR_PRX | SONIC_RCR_LBK | SONIC_RCR_FAER |
  643. SONIC_RCR_CRCR | SONIC_RCR_LPKT | SONIC_RCR_BC | SONIC_RCR_MC);
  644. packet_type = receive_filter(s, buf, size);
  645. if (packet_type < 0) {
  646. DPRINTF("packet not for netcard\n");
  647. return -1;
  648. }
  649. /* XXX: Check byte ordering */
  650. /* Check for EOL */
  651. if (s->regs[SONIC_LLFA] & 0x1) {
  652. /* Are we still in resource exhaustion? */
  653. size = sizeof(uint16_t) * 1 * width;
  654. address = ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width;
  655. s->memory_rw(s->mem_opaque, address, (uint8_t*)data, size, 0);
  656. if (data[0 * width] & 0x1) {
  657. /* Still EOL ; stop reception */
  658. return -1;
  659. } else {
  660. s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
  661. }
  662. }
  663. /* Save current position */
  664. s->regs[SONIC_TRBA1] = s->regs[SONIC_CRBA1];
  665. s->regs[SONIC_TRBA0] = s->regs[SONIC_CRBA0];
  666. /* Calculate the ethernet checksum */
  667. #ifdef SONIC_CALCULATE_RXCRC
  668. checksum = cpu_to_le32(crc32(0, buf, rx_len));
  669. #else
  670. checksum = 0;
  671. #endif
  672. /* Put packet into RBA */
  673. DPRINTF("Receive packet at %08x\n", (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0]);
  674. address = (s->regs[SONIC_CRBA1] << 16) | s->regs[SONIC_CRBA0];
  675. s->memory_rw(s->mem_opaque, address, (uint8_t*)buf, rx_len, 1);
  676. address += rx_len;
  677. s->memory_rw(s->mem_opaque, address, (uint8_t*)&checksum, 4, 1);
  678. rx_len += 4;
  679. s->regs[SONIC_CRBA1] = address >> 16;
  680. s->regs[SONIC_CRBA0] = address & 0xffff;
  681. available = (s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0];
  682. available -= rx_len / 2;
  683. s->regs[SONIC_RBWC1] = available >> 16;
  684. s->regs[SONIC_RBWC0] = available & 0xffff;
  685. /* Update status */
  686. if (((s->regs[SONIC_RBWC1] << 16) | s->regs[SONIC_RBWC0]) < s->regs[SONIC_EOBC]) {
  687. s->regs[SONIC_RCR] |= SONIC_RCR_LPKT;
  688. }
  689. s->regs[SONIC_RCR] |= packet_type;
  690. s->regs[SONIC_RCR] |= SONIC_RCR_PRX;
  691. if (s->loopback_packet) {
  692. s->regs[SONIC_RCR] |= SONIC_RCR_LBK;
  693. s->loopback_packet = 0;
  694. }
  695. /* Write status to memory */
  696. DPRINTF("Write status at %08x\n", (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]);
  697. data[0 * width] = s->regs[SONIC_RCR]; /* status */
  698. data[1 * width] = rx_len; /* byte count */
  699. data[2 * width] = s->regs[SONIC_TRBA0]; /* pkt_ptr0 */
  700. data[3 * width] = s->regs[SONIC_TRBA1]; /* pkt_ptr1 */
  701. data[4 * width] = s->regs[SONIC_RSC]; /* seq_no */
  702. size = sizeof(uint16_t) * 5 * width;
  703. s->memory_rw(s->mem_opaque, (s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA], (uint8_t *)data, size, 1);
  704. /* Move to next descriptor */
  705. size = sizeof(uint16_t) * width;
  706. s->memory_rw(s->mem_opaque,
  707. ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 5 * width,
  708. (uint8_t *)data, size, 0);
  709. s->regs[SONIC_LLFA] = data[0 * width];
  710. if (s->regs[SONIC_LLFA] & 0x1) {
  711. /* EOL detected */
  712. s->regs[SONIC_ISR] |= SONIC_ISR_RDE;
  713. } else {
  714. data[0 * width] = 0; /* in_use */
  715. s->memory_rw(s->mem_opaque,
  716. ((s->regs[SONIC_URDA] << 16) | s->regs[SONIC_CRDA]) + sizeof(uint16_t) * 6 * width,
  717. (uint8_t *)data, size, 1);
  718. s->regs[SONIC_CRDA] = s->regs[SONIC_LLFA];
  719. s->regs[SONIC_ISR] |= SONIC_ISR_PKTRX;
  720. s->regs[SONIC_RSC] = (s->regs[SONIC_RSC] & 0xff00) | (((s->regs[SONIC_RSC] & 0x00ff) + 1) & 0x00ff);
  721. if (s->regs[SONIC_RCR] & SONIC_RCR_LPKT) {
  722. /* Read next RRA */
  723. do_read_rra(s);
  724. }
  725. }
  726. /* Done */
  727. dp8393x_update_irq(s);
  728. return size;
  729. }
  730. static void nic_reset(void *opaque)
  731. {
  732. dp8393xState *s = opaque;
  733. qemu_del_timer(s->watchdog);
  734. s->regs[SONIC_CR] = SONIC_CR_RST | SONIC_CR_STP | SONIC_CR_RXDIS;
  735. s->regs[SONIC_DCR] &= ~(SONIC_DCR_EXBUS | SONIC_DCR_LBR);
  736. s->regs[SONIC_RCR] &= ~(SONIC_RCR_LB0 | SONIC_RCR_LB1 | SONIC_RCR_BRD | SONIC_RCR_RNT);
  737. s->regs[SONIC_TCR] |= SONIC_TCR_NCRS | SONIC_TCR_PTX;
  738. s->regs[SONIC_TCR] &= ~SONIC_TCR_BCM;
  739. s->regs[SONIC_IMR] = 0;
  740. s->regs[SONIC_ISR] = 0;
  741. s->regs[SONIC_DCR2] = 0;
  742. s->regs[SONIC_EOBC] = 0x02F8;
  743. s->regs[SONIC_RSC] = 0;
  744. s->regs[SONIC_CE] = 0;
  745. s->regs[SONIC_RSC] = 0;
  746. /* Network cable is connected */
  747. s->regs[SONIC_RCR] |= SONIC_RCR_CRS;
  748. dp8393x_update_irq(s);
  749. }
  750. static void nic_cleanup(VLANClientState *nc)
  751. {
  752. dp8393xState *s = DO_UPCAST(NICState, nc, nc)->opaque;
  753. cpu_unregister_io_memory(s->mmio_index);
  754. qemu_del_timer(s->watchdog);
  755. qemu_free_timer(s->watchdog);
  756. qemu_free(s);
  757. }
  758. static NetClientInfo net_dp83932_info = {
  759. .type = NET_CLIENT_TYPE_NIC,
  760. .size = sizeof(NICState),
  761. .can_receive = nic_can_receive,
  762. .receive = nic_receive,
  763. .cleanup = nic_cleanup,
  764. };
  765. void dp83932_init(NICInfo *nd, target_phys_addr_t base, int it_shift,
  766. qemu_irq irq, void* mem_opaque,
  767. void (*memory_rw)(void *opaque, target_phys_addr_t addr, uint8_t *buf, int len, int is_write))
  768. {
  769. dp8393xState *s;
  770. qemu_check_nic_model(nd, "dp83932");
  771. s = qemu_mallocz(sizeof(dp8393xState));
  772. s->mem_opaque = mem_opaque;
  773. s->memory_rw = memory_rw;
  774. s->it_shift = it_shift;
  775. s->irq = irq;
  776. s->watchdog = qemu_new_timer_ns(vm_clock, dp8393x_watchdog, s);
  777. s->regs[SONIC_SR] = 0x0004; /* only revision recognized by Linux */
  778. s->conf.macaddr = nd->macaddr;
  779. s->conf.vlan = nd->vlan;
  780. s->conf.peer = nd->netdev;
  781. s->nic = qemu_new_nic(&net_dp83932_info, &s->conf, nd->model, nd->name, s);
  782. qemu_format_nic_info_str(&s->nic->nc, s->conf.macaddr.a);
  783. qemu_register_reset(nic_reset, s);
  784. nic_reset(s);
  785. s->mmio_index = cpu_register_io_memory(dp8393x_read, dp8393x_write, s,
  786. DEVICE_NATIVE_ENDIAN);
  787. cpu_register_physical_memory(base, 0x40 << it_shift, s->mmio_index);
  788. }