Guest User

Untitled

a guest
Dec 15th, 2018
94
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 21.00 KB | None | 0 0
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "io.h"
  7. #include "ureg.h"
  8. #include "../port/error.h"
  9.  
  10. #include "../port/netif.h"
  11. #include "etherif.h"
  12. #include "ethermii.h"
  13. //
  14. //
  15. // Virtio
  16. //
  17. //
  18. typedef struct Vioreqhdr Vioreqhdr;
  19. typedef struct Vringhdr Vringhdr;
  20. typedef struct Vdesc Vdesc;
  21. typedef struct Vused Vused;
  22. typedef struct Vqueue Vqueue;
  23. typedef struct Vdev Vdev;
  24.  
  25. enum {
  26. Acknowledge = 1,
  27. Driver = 2,
  28. DriverOk = 4,
  29. Failed = 128,
  30. };
  31.  
  32. enum {
  33. Devfeat = 0,
  34. Drvfeat = 4,
  35. Qaddr = 8,
  36. Qsize = 12,
  37. Qselect = 14,
  38. Qnotify = 16,
  39. Status = 18,
  40. Isr = 19,
  41.  
  42. Devspec = 20,
  43. };
  44.  
  45. enum {
  46. Next = 1,
  47. Write = 2,
  48. Indirect = 4,
  49. };
  50.  
  51. enum {
  52. VIRTIO_F_NOTIFY_ON_EMPTY = (1 << 24),
  53. VIRTIO_F_RING_INDIRECT_DESC = (1 << 28),
  54. VIRTIO_F_RING_EVENT_IDX = (1 << 29),
  55. };
  56.  
  57. enum {
  58. VRING_AVAIL_F_NO_INTERRUPT = (1 << 0),
  59. };
  60.  
  61. struct Vioreqhdr
  62. {
  63. u32int typ;
  64. u32int prio;
  65. u64int lba;
  66. };
  67.  
  68. struct Vringhdr
  69. {
  70. u16int flags;
  71. u16int idx;
  72. };
  73.  
  74. struct Vdesc
  75. {
  76. u64int addr;
  77. u32int len;
  78. u16int flags;
  79. u16int next;
  80. };
  81.  
  82. struct Vused
  83. {
  84. u32int id;
  85. u32int len;
  86. };
  87.  
  88. struct Key
  89. {
  90. void* kaddr;
  91. ulong paddr;
  92. };
  93. typedef struct Key Key;
  94.  
  95. struct Vqueue
  96. {
  97. int size;
  98.  
  99. int free;
  100. int nfree;
  101.  
  102. Vdesc *desc;
  103.  
  104. Vringhdr *avail;
  105. u16int *availent;
  106. u16int *availevent;
  107.  
  108. Vringhdr *used;
  109. Vused *usedent;
  110. u16int *usedevent;
  111.  
  112. u16int lastused;
  113.  
  114. Key *key;
  115.  
  116. Rendez;
  117. QLock;
  118. Lock;
  119. };
  120.  
  121. struct Vdev
  122. {
  123. int typ;
  124.  
  125. Pcidev *pci;
  126.  
  127. ulong port;
  128. ulong features;
  129.  
  130. int nqueue;
  131. Vqueue *queue[16];
  132.  
  133. int active;
  134.  
  135. Vdev *next;
  136. };
  137.  
  138. static Vqueue*
  139. mkvqueue(int size)
  140. {
  141. Vqueue *q;
  142. uchar *p;
  143. int i;
  144.  
  145. q = malloc(sizeof(*q));
  146. p = mallocalign(
  147. PGROUND(sizeof(Vdesc)*size +
  148. sizeof(Vringhdr) +
  149. sizeof(u16int)*size +
  150. sizeof(u16int)) +
  151. PGROUND(sizeof(Vringhdr) +
  152. sizeof(Vused)*size +
  153. sizeof(u16int)),
  154. BY2PG, 0, 0);
  155. if(p == nil || q == nil){
  156. print("mkvqueue: no memory for Vqueue\n");
  157. free(p);
  158. free(q);
  159. return nil;
  160. }
  161.  
  162. q->desc = (void*)p;
  163. p += sizeof(Vdesc)*size;
  164. q->avail = (void*)p;
  165. p += sizeof(Vringhdr);
  166. q->availent = (void*)p;
  167. p += sizeof(u16int)*size;
  168. q->availevent = (void*)p;
  169. p += sizeof(u16int);
  170.  
  171. p = (uchar*)PGROUND((ulong)p);
  172. q->used = (void*)p;
  173. p += sizeof(Vringhdr);
  174. q->usedent = (void*)p;
  175. p += sizeof(Vused)*size;
  176. q->usedevent = (void*)p;
  177.  
  178. q->key = malloc(sizeof(Key) * size);
  179.  
  180. q->free = -1;
  181. q->nfree = q->size = size;
  182. for(i=0; i<size; i++){
  183. q->desc[i].next = q->free;
  184. q->free = i;
  185. }
  186.  
  187. return q;
  188. }
  189.  
  190. //
  191. //
  192. // Virtio-Net specific
  193. //
  194. //
  195. typedef struct Vnetcfg Vnetcfg;
  196. typedef struct Vnetctrl Vnetctrl;
  197.  
  198. /* Virtio-net queue number */
  199. enum {
  200. VIRTIO_NET_Q_RX = 0,
  201. VIRTIO_NET_Q_TX = 1,
  202. VIRTIO_NET_Q_CTLR = 2,
  203. };
  204.  
  205. /* Virtio-net specific Device features */
  206. enum {
  207. VIRTIO_NET_F_CSUM = (1 << 0),
  208. VIRTIO_NET_F_GUEST_CSUM = (1 << 1),
  209. VIRTIO_NET_F_MAC = (1 << 5),
  210. VIRTIO_NET_F_GSO = (1 << 6),
  211. VIRTIO_NET_F_GUEST_TSO4 = (1 << 7),
  212. VIRTIO_NET_F_GUEST_TSO6 = (1 << 8),
  213. VIRTIO_NET_F_GUEST_ECN = (1 << 9),
  214. VIRTIO_NET_F_GUEST_UFO = (1 << 10),
  215. VIRTIO_NET_F_HOST_TSO4 = (1 << 11),
  216. VIRTIO_NET_F_HOST_TSO6 = (1 << 12),
  217. VIRTIO_NET_F_HOST_ECN = (1 << 13),
  218. VIRTIO_NET_F_HOST_UFO = (1 << 14),
  219. VIRTIO_NET_F_MRG_RXBUF = (1 << 15),
  220. VIRTIO_NET_F_STATUS = (1 << 16),
  221. VIRTIO_NET_F_CTRL_VQ = (1 << 17),
  222. VIRTIO_NET_F_CTRL_RX = (1 << 18),
  223. VIRTIO_NET_F_CTRL_VLAN = (1 << 19),
  224. VIRTIO_NET_F_GUEST_ANNOUNCE = (1 << 21),
  225. };
  226.  
  227. /* Virtio-net Device Status */
  228. enum {
  229. VIRTIO_NET_S_LINK_UP = 1,
  230. VIRTIO_NET_S_ANNOUNCE = 2,
  231. };
  232.  
  233. /* Not used : Virtio-net Device Specific Region */
  234. struct Vnetcfg {
  235. u8int mac[6];
  236. u16int status;
  237. };
  238.  
  239. /* Vnetreqhdr, flags */
  240. enum {
  241. VIRTIO_NET_HDR_F_NEEDS_CSUM =~1,
  242. };
  243.  
  244. /* Vnetreqhdr, gso_type */
  245. enum {
  246. VIRTIO_NET_HDR_GSO_NONE = 0,
  247. VIRTIO_NET_HDR_GSO_TCPV4 = 1,
  248. VIRTIO_NET_HDR_GSO_UDP = 3,
  249. VIRTIO_NET_HDR_GSO_TCPV6 = 4,
  250. VIRTIO_NET_HDR_GSO_ECN = 0x80,
  251. };
  252.  
  253. /* Virtio-net request header */
  254. #pragma pack on
  255. typedef struct Vnetreqhdr Vnetreqhdr;
  256. struct Vnetreqhdr {
  257. u8int flags;
  258. u8int gso_type;
  259. u16int hdr_len;
  260. u16int gso_size;
  261. u16int csum_start;
  262. u16int csum_offset;
  263. };
  264. #pragma pack off
  265. int Vnetreqhdrsize = 10;
  266.  
  267. /* Virtio-Net Control Requext Class */
  268. enum {
  269. VIRTIO_NET_CTRL_RX_CLASS = 0,
  270. };
  271.  
  272. /* Virtio-net Control Request Command */
  273. enum {
  274. VIRTIO_NET_CTRL_RX_CMD_PROMISC = 0,
  275. VIRTIO_NET_CTRL_RX_CMD_ALLMULTI = 1,
  276. };
  277.  
  278. /* on off */
  279. enum {
  280. VIRTIO_NET_CTRL_RX_OFF = 0,
  281. VIRTIO_NET_CTRL_RX_ON = 1,
  282. };
  283.  
  284. /* ack value */
  285. enum {
  286. VIRTIO_NET_CTRL_ACK_OK = 0,
  287. VIRTIO_NET_CTRL_ACK_ERR = 1,
  288. };
  289.  
  290. /* Virtio-net control request */
  291. struct Vnetctrl {
  292. u8int class;
  293. u8int command;
  294. };
  295. /* followed by u8int onoff, u8int ack */
  296.  
  297. Vdev *vionethead = nil;
  298. Vdev *vionettail = nil;
  299.  
  300. /////////////////////////////////////////////////////////////////////
  301. // Virtio-net helper funcs
  302. /////////////////////////////////////////////////////////////////////
  303. /*********** Interrupt ***********/
  304. /*
  305. * Free descriptors used for this transmit
  306. */
  307. static void
  308. vionettxfree(Vqueue* q, int head)
  309. {
  310. Vdesc *d;
  311. int bufid;
  312. Vdesc *bufd;
  313. //ulong paddr;
  314. //void* kaddr;
  315. Block *bp;
  316. Vnetreqhdr *vnetreqhdr;
  317. print("txfree q %p head %d\n", q, head);
  318.  
  319. /* get Vnetreqhdr */
  320. d = &q->desc[head];
  321.  
  322. /* Vnetreqhdr is followed by real buffer descriptor */
  323. bufid = d->next;
  324. bufd = &q->desc[bufid];
  325.  
  326. /* free header */
  327. vnetreqhdr = q->key[head].kaddr;
  328. free(vnetreqhdr);
  329. d->len = d->flags = 0;
  330. q->key[head].kaddr = nil;
  331.  
  332. /* calculate original Block address and free */
  333. bp = q->key[bufid].kaddr;
  334. freeb(bp);
  335. q->key[bufid].kaddr = nil;
  336.  
  337. /* put vdesc for header back */
  338. d->next = q->free;
  339. q->free = head;
  340. q->nfree++;
  341.  
  342. /* pub vdesc for buffer back */
  343. bufd->next = q->free;
  344. q->free = bufid;
  345. q->nfree++;
  346. }
  347.  
  348. /*
  349. * Interrupt on Tx vq.
  350. * responsible for checking vq change and cleanup
  351. */
  352. static void
  353. vionettxinterrupt(Vdev* vd)
  354. {
  355. Vqueue* q;
  356. int id, m;
  357.  
  358. print("txinterrupt : in\n");
  359. q = vd->queue[VIRTIO_NET_Q_TX];
  360. print("txinterrupt : vd = %p\n", vd);
  361. print("txinterrupt : q= %p\n", q);
  362. m = (q->size-1);
  363.  
  364. //lock(q);
  365. print("txinterrupt: %d ?? %d\n",
  366. (q->lastused % m), (q->used->idx &m));
  367. while((q->lastused % m) != (q->used->idx % m)) {
  368. id = q->usedent[q->lastused++ % (q->size-1)].id;
  369. vionettxfree(q, id);
  370. }
  371. //unlock(q);
  372. print("txinterrupt : out\n");
  373. }
  374.  
  375. static void
  376. vionetrxproc(Ether* edev, Vqueue* q, int id)
  377. {
  378. Vdesc* d;
  379. Vdesc* bufd;
  380. void* buf;
  381. Block *bp;
  382. Vnetreqhdr* vnetreqhdr;
  383.  
  384. d = &q->desc[id];
  385. bufd = &q->desc[d->next];
  386.  
  387. vnetreqhdr = (Vnetreqhdr*)q->key[id].kaddr;
  388.  
  389. print("rxproc : d %p len %d\n", d, d->len);
  390. print("rxporc : vnetreqhdr %p flags %d len %d\n",
  391. vnetreqhdr, vnetreqhdr->flags, vnetreqhdr->hdr_len);
  392. print("rxproc : bufd %p size %d\n", bufd, bufd->len);
  393.  
  394. buf = (void*)q->key[d->next].kaddr;
  395.  
  396. bp = iallocb(ETHERMAXTU); // XXX
  397. memmove(bp->rp, buf, ETHERMAXTU); // XXX
  398.  
  399. bp->wp += ETHERMAXTU;
  400. bp->lim = bp->wp; /* lie like a dog */
  401.  
  402. /* go up */
  403. etheriq(edev, bp, 1);
  404.  
  405. /* clean current buffer : XXX */
  406. d->len = sizeof(Vnetreqhdr);
  407. d->flags = Next|Write;
  408. vnetreqhdr->hdr_len = ETHERMAXTU;
  409. bufd->len = ETHERMAXTU;
  410. bufd->flags = Write;
  411. }
  412.  
  413. static void
  414. vionetrxinterrupt(Ether* edev)
  415. {
  416. Vqueue* q;
  417. int id, m;
  418. Vdev* vd;
  419. int i, head;
  420.  
  421. print("vionetrxinterrupt: in, edev %p\n", edev);
  422.  
  423. vd = edev->ctlr;
  424. print("vionetrxinterrupt: in, vd %p\n", vd);
  425. q = vd->queue[VIRTIO_NET_Q_RX];
  426. print("vionetrxinterrupt: in, q %p\n", q);
  427. m = (q->size-1);
  428.  
  429. //lock(q);
  430. print("vionetrxinterrupt: forward and process lastused %d to used->idx %d\n",
  431. q->lastused, q->used->idx);
  432. i = 0;
  433. while((q->lastused % m) != (q->used->idx % m)) {
  434. id = q->usedent[q->lastused++ % m].id;
  435. vionetrxproc(edev, q, id);
  436. /*
  437. * here id is free. we do push back to free list?
  438. * NO. push back to avail ring as is.
  439. */
  440. coherence();
  441. i++;
  442. q->availent[(q->avail->idx++) % m] = id;
  443. }
  444. coherence();
  445. if (i) {
  446. coherence();
  447. outs(vd->port+Qnotify, VIRTIO_NET_Q_RX);
  448. }
  449. print("vionetrxinterrupt: fixedup receive buffer\n");
  450.  
  451. print("vionetrxinterrupt: out\n");
  452. }
  453.  
  454. /************ Initialize ****************/
  455. static void
  456. vionettxinit(Vdev* vd)
  457. {
  458. print("vionettxinit: in\n");
  459. if (vd->nqueue < 2) {
  460. return;
  461. }
  462.  
  463. /* no interrupt */
  464. print("vionettxinit: in\n");
  465. // vd->queue[VIRTIO_NET_Q_RX]->avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
  466. print("vionettxinit: in\n");
  467.  
  468. vd->queue[VIRTIO_NET_Q_RX]->lastused = 0;
  469. print("vionettxinit: out\n");
  470. }
  471.  
  472. static int
  473. vionetrxinithead(Vqueue* q)
  474. {
  475. Vdesc* d;
  476. int head, free;
  477. Vnetreqhdr* vnetreqhdr;
  478. void* buf;
  479.  
  480. if (q->nfree < 2)
  481. return -1;
  482.  
  483. head = free = q->free;
  484. d = &q->desc[free];
  485. /* setup Vnethdr */
  486. vnetreqhdr = malloc(sizeof(Vnetreqhdr));
  487. vnetreqhdr->hdr_len = ETHERMAXTU;//sizeof(Vnetreqhdr);
  488. vnetreqhdr->flags = 0; // XXX
  489. // vnetreqhdr->num_buffers = 1;
  490. /* setup vdesc for Vnetreqhdr */
  491. d->addr = PADDR(vnetreqhdr);
  492. d->len = Vnetreqhdrsize;//sizeof(Vnetreqhdr);
  493. d->flags = Next|Write ;
  494. /* save key */
  495. q->key[head].paddr = d->addr;
  496. q->key[head].kaddr = vnetreqhdr;
  497. free = d->next;
  498.  
  499. /* get vdesc for data buffer : a real frame */
  500. d = &q->desc[free];
  501. /* setup vdesc */
  502. buf = malloc(ETHERMAXTU);
  503. d->addr = PADDR(buf);
  504. d->len = ETHERMAXTU;
  505. d->flags = Write;
  506. /* save key */
  507. q->key[free].paddr = d->addr;
  508. q->key[free].kaddr = buf;
  509. free = d->next;
  510.  
  511. q->nfree -= 2;
  512. q->free = free;
  513.  
  514. return head;
  515. }
  516.  
  517. static void
  518. vionetrxinit(Vdev* vd)
  519. {
  520. Vqueue *q;
  521. Vdesc *d;
  522. int nadded;
  523. int head, free;
  524. Vnetreqhdr* vnetreqhdr;
  525. void* buf;
  526.  
  527.  
  528. print("vionetrxinit: in\n");
  529. if (vd->nqueue < 1) {
  530. return;
  531. }
  532.  
  533. print("vionetrxinit: fetch queuen\n");
  534. q = vd->queue[VIRTIO_NET_Q_RX];
  535.  
  536. print("vionetrxinit: each vdesc has %d byte buffer\n", ETHERMAXTU);
  537. /*
  538. q->avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
  539. */
  540.  
  541. print("vionetrxinit: allocating buffer\n");
  542. /* allocate receive buffer */
  543. nadded = 0;
  544. while(1) {
  545. head = vionetrxinithead(q);
  546. if (head < 0)
  547. break;
  548.  
  549. coherence();
  550. /* put head's number into avail ring */
  551. nadded++;
  552. q->availent[(q->avail->idx++) % (q->size-1)] = head;
  553. coherence();
  554. }
  555. if (nadded > 0) {
  556. coherence();
  557. /* update avail idx */
  558. coherence();
  559. outs(vd->port+Qnotify, VIRTIO_NET_Q_RX);
  560. }
  561. print("vionetrxinit: allocated %d buffers\n", nadded);
  562.  
  563. q->lastused = 0;
  564.  
  565. print("vionettxinit: out\n");
  566. }
  567.  
  568. static void
  569. vionetvqinit(Vdev* vd)
  570. {
  571. int i;
  572. int size;
  573. u32int a;
  574.  
  575.  
  576. for (i = 0; i < nelem(vd->queue) ; i++) {
  577. /* select operating queue */
  578. outs(vd->port + Qselect, i);
  579. /* get operating queue size (0 : disabled) */
  580. if ((size = ins(vd->port + Qsize)) == 0)
  581. break;
  582. if ((vd->queue[i] = mkvqueue(size)) == nil)
  583. break;
  584. coherence();
  585. a = PADDR(vd->queue[i]->desc)/BY2PG;
  586. /* write addr of operating queue at Qaddr */
  587. outl(vd->port + Qaddr, a);
  588. }
  589. vd->nqueue = i;
  590.  
  591. /* setup rx */
  592. vionettxinit(vd);
  593.  
  594. /* setup tx */
  595. vionetrxinit(vd);
  596. }
  597.  
  598. /*
  599. * Negotiates Device features and given Driver features
  600. */
  601. static ulong
  602. vio_negotiate_feature(Vdev *vd, ulong drvfeat)
  603. {
  604. ulong features;
  605.  
  606. print("vio neto fet: in %ld + %d\n", vd->port, Devfeat);
  607. /* read device features */
  608. features = inl(vd->port + Devfeat);
  609.  
  610. print("vio neto fet: in sec\n");
  611. features &= drvfeat;
  612.  
  613. print("vio neto fet: out %ld %d\n", vd->port, Drvfeat);
  614. /* write back features */
  615. outl(vd->port + Drvfeat, features);
  616.  
  617. print("vio neto fet: out\n");
  618. return features;
  619. }
  620.  
  621. static void
  622. vionetinit1(Ether* edev, Vdev* vd)
  623. {
  624. int i;
  625.  
  626. print("vionetinit1: in\n");
  627. /* check feature bit : F_MAC */
  628. if (vd->features & VIRTIO_NET_F_MAC) {
  629. for (i = 0; i < 6; i++) {
  630. edev->ea[i] = inb(vd->port + Devspec + i);
  631. }
  632. } else {
  633. for (i = 0; i < 6; i++) {
  634. edev->ea[i] = 0xff;
  635. outb(vd->port + Devspec + i, edev->ea[i]);
  636. }
  637. }
  638.  
  639.  
  640. /* check feature bit : F_STATUS */
  641. if (vd->features & VIRTIO_NET_F_STATUS) {
  642. /* check and up the link */
  643. edev->link = (0x01 & ins(vd->port + Devspec + Eaddrlen));
  644. print("vionetinit1: link is %d\n", edev->link);
  645. edev->link &= 0x01;
  646. print("vionetinit1: link is %d\n", edev->link);
  647. outs(vd->port + Devspec + Eaddrlen, edev->link);
  648. } else {
  649. /* spec says assume active */
  650. edev->link = 0x01;
  651. }
  652. print("vionetinit1: out\n");
  653. }
  654.  
  655. /*
  656. * Initialize device&driver
  657. */
  658. static void
  659. vionetinit(Vdev* vd)
  660. {
  661. int is_ctrl_vq = 0;
  662.  
  663. print("vionetinit: in\n");
  664. /* negotiate features */
  665. vd->features = vio_negotiate_feature(vd,
  666. VIRTIO_F_NOTIFY_ON_EMPTY |
  667. VIRTIO_NET_F_MAC |
  668. VIRTIO_NET_F_STATUS |
  669. // VIRTIO_NET_F_CTRL_VQ |
  670. VIRTIO_NET_F_CTRL_RX |
  671. 0
  672. );
  673.  
  674. print("vionetinit: negotiated\n");
  675. /* negotiate features */
  676. /* check feature bit : F_CTRL_VQ */
  677. if (vd->features & VIRTIO_NET_F_CTRL_VQ) {
  678. is_ctrl_vq = 1;
  679. }
  680.  
  681. /* setup virtqueue */
  682. print("vionetinit: call vionetvqinit\n");
  683. vionetvqinit(vd);
  684. print("vionetinit: called vionetvqinit\n");
  685.  
  686. /* check if ctrlvq is valid */
  687. if (is_ctrl_vq && vd->nqueue != 3) {
  688. print("vionetinit(): ctrl queue is invalid\n");
  689. }
  690.  
  691. print("vionetinit: out\n");
  692. return;
  693. }
  694.  
  695. /////////////////////////////////////////////////////////////////////
  696. // Generic Network driver funcs
  697. /////////////////////////////////////////////////////////////////////
  698. static void
  699. vionetattach(Ether*)
  700. {
  701. /* nothing to do */
  702. }
  703.  
  704. void
  705. vionettransmit(Ether* edev)
  706. {
  707. Block* bp; /* bp->rp has address */
  708. Vdev* vd;
  709. int head, free;
  710. Vdesc *d;
  711. Vqueue *q;
  712. int nadded = 0;
  713. Vnetreqhdr* vnetreqhdr;
  714.  
  715. vd = edev->ctlr;
  716. q = vd->queue[VIRTIO_NET_Q_TX];
  717.  
  718. print("vionettransmit: in\n");
  719. //lock(q);
  720.  
  721. for (;;) {
  722. /* needs 2 entries for transmit */
  723. if (q->nfree < 2) {
  724. //unlock(q);
  725. //error("out of virtio descriptors");
  726. print("vionettransmit: run out of queue : break;\n");
  727. break;
  728. }
  729.  
  730. /* get next frame to send */
  731. if ((bp = qget(edev->oq)) == nil) {
  732. print("vionettransmit: run out of oq : break;\n");
  733. break;
  734. }
  735.  
  736. head = free = q->free;
  737.  
  738. print("vionettransmit: head is %d\n", head);
  739. /* get vdesc for Vnethdr */
  740. d = &q->desc[free]; free = d->next;
  741.  
  742. /* setup Vnethdr */
  743. vnetreqhdr = malloc(Vnetreqhdrsize/*sizeof(Vnetreqhdr)*/);
  744. // vnetreqhdr->hdr_len = Vnetreqhdrsize;//sizeof(Vnetreqhdr);
  745. vnetreqhdr->flags = 0; // XXX
  746. // vnetreqhdr->num_buffers = 1;
  747.  
  748. /* setup vdesc for Vnethdr */
  749. d->addr = PADDR(vnetreqhdr);
  750. d->len = Vnetreqhdrsize;//sizeof(Vnetreqhdr);
  751. d->flags = Next;
  752.  
  753. /* save paddr and kaddr */
  754. q->key[head].paddr = d->addr;
  755. q->key[head].kaddr = vnetreqhdr;
  756.  
  757. /* get vdesc for data buffer : a real frame */
  758. print("vionettransmit: buffer is %d\n", free);
  759. d = &q->desc[free]; free = d->next;
  760.  
  761. /* setup vdesc for data buffer */
  762. d->addr = PADDR(bp->rp);
  763. d->len = BLEN(bp);
  764. d->flags = 0;
  765.  
  766. /* save paddr and kaddr , paddr */
  767. q->key[free].paddr = d->addr;
  768. q->key[free].kaddr = bp;
  769.  
  770. print("vionettransmit: q->free %d, q->nfree %d\n", q->free, q->nfree);
  771. q->nfree -= 2;
  772. q->free = free;
  773.  
  774. coherence();
  775. /* put head's number into avail ring */
  776. print("vionettransmit: set head %d at idx %d + nadded %d q->size %d\n",
  777. head, q->avail->idx, nadded, q->size);
  778. nadded++;
  779. /* update avail idx */
  780. q->availent[(q->avail->idx++) & (q->size-1)] = head;
  781. coherence();
  782. print("vionettransmit: nadded is %d q->free %d, q->nfree %d\n",
  783. nadded, q->free, q->nfree);
  784. }
  785.  
  786. coherence();
  787. //unlock(q);
  788. if (nadded > 0) {
  789. print("vionettransmit: updated idx to %d\n", q->avail->idx);
  790. /* notify */
  791. outs(vd->port+Qnotify, VIRTIO_NET_Q_TX);
  792. }
  793.  
  794. print("vionettransmit: done\n");
  795. print("vionettransmit: out\n");
  796. }
  797.  
  798. static void
  799. vionetinterrupt(Ureg*, void* arg)
  800. {
  801. Vdev *vd;
  802. Ether *edev;
  803.  
  804. edev = arg;
  805. vd = edev->ctlr;
  806.  
  807. if (edev == nil || vd == nil)
  808. return;
  809.  
  810. print("vionetinterrupt: in edev %p vd %p\n", edev, vd);
  811. if (inb(vd->port + Isr) & 1) {
  812. print("vionetinterrupt: in Isr\n");
  813. /* wakeup ctrl op */
  814. // if (vd->nqueue > VIRTIO_NET_Q_CTLR) {
  815. // wakeup(vd->queue[VIRTIO_NET_Q_CTLR]);
  816. // }
  817.  
  818. /* control vq */
  819. // vionetctrlinterrupt(vd);
  820.  
  821. /* transmit vq */
  822. print("vionetinterrupt: in tx\n");
  823. vionettxinterrupt(vd);
  824.  
  825. /* receive vq */
  826. print("vionetinterrupt: in rx\n");
  827. vionetrxinterrupt(edev);
  828. print("vionetinterrupt: in done\n");
  829. }
  830.  
  831. if (inb(vd->port + Isr) & 2) {
  832. /* config space has changed */
  833. print("vionetinterrupt: config changed\n");
  834. }
  835. print("vionetinterrupt: out\n");
  836. }
  837.  
  838. static long
  839. vionetifstat(Ether*, void*, long, ulong)
  840. {
  841. return 0;
  842. }
  843.  
  844. static void
  845. vionetshutdown()
  846. {
  847. /* do cleanup */
  848. return;
  849. }
  850.  
  851. static long
  852. vionetctl(Ether*, void*, long)
  853. {
  854. /* do nothing */
  855. return 0;
  856. }
  857.  
  858. /*
  859. static void
  860. vionetdone(void *arg)
  861. {
  862. struct Rock *r;
  863. Vqueue *q;
  864. u16int i;
  865.  
  866. r = arg;
  867. q = r->q;
  868.  
  869. for (i = q->lastused; i != q->used->idx; i++) {
  870. if (q->usedent[i % q->size].id == r->id) {
  871. if (i == q->lastused)
  872. q->lastused++;
  873. r->done =1;
  874. break;
  875. }
  876. }
  877.  
  878. return r->done;
  879. }
  880. */
  881.  
  882.  
  883. /*
  884. static void
  885. vionetwait(Vqueue *q, int id)
  886. {
  887. struct Rock r;
  888.  
  889. r.q = q;
  890. r.id = id;
  891. r.done = 0;
  892. do {
  893. //qlock(q);
  894. while(waserror());
  895.  
  896. sleep(q, vionetdone, &r);
  897. poperror();
  898. //qunlock(q);
  899. } while(!r.done);
  900. }
  901. */
  902.  
  903. /*
  904. * Send Control request to device.
  905. */
  906. static void
  907. vionetctrl(Ether* edev, u8int cmd, u8int on)
  908. {
  909. Vnetctrl vnetctrl;
  910. Vdev* vd;
  911. Vqueue* q;
  912. int free, head;
  913. Vdesc *d;
  914. u8int ack;
  915. u8int onoff;
  916.  
  917. vd = edev->ctlr;
  918. onoff = on ? VIRTIO_NET_CTRL_RX_ON : VIRTIO_NET_CTRL_RX_OFF;
  919. ack = VIRTIO_NET_CTRL_ACK_ERR;
  920.  
  921. q = vd->queue[VIRTIO_NET_Q_CTLR];
  922. //lock(q);
  923.  
  924. /* get idx of head of free entry */
  925. head = free = q->free;
  926.  
  927. /* allocate Vnetctrl entry */
  928.  
  929. vnetctrl.class = VIRTIO_NET_CTRL_RX_CLASS;
  930. vnetctrl.command = cmd;
  931.  
  932. /* push vnetctrl */
  933. d = &q->desc[free]; free = d->next;
  934. d->addr = PADDR(&vnetctrl);
  935. d->len = sizeof(vnetctrl);
  936. d->flags = Next;
  937.  
  938. /* push onoff */
  939. d = &q->desc[free]; free = d->next;
  940. d->addr = PADDR(&onoff);
  941. d->len = sizeof(u8int);
  942. d->flags = Next;
  943.  
  944. /* push ack */
  945. d = &q->desc[free]; free = d->next;
  946. d->addr = PADDR(&ack);
  947. d->len = sizeof(u8int);
  948. d->flags = Write;
  949. d->next = -1;
  950.  
  951. q->free = free;
  952. q->nfree -= 3; /* pushed 3 */
  953.  
  954. coherence(); /* sync */
  955.  
  956. q->availent[q->avail->idx++ & q->size] = head;
  957.  
  958. //unlock(q);
  959.  
  960. coherence();
  961.  
  962. /* commit notify */
  963. outs(vd->port + Qnotify, VIRTIO_NET_Q_CTLR);
  964.  
  965. /* blocking */
  966. //vionetwait(q, head);
  967.  
  968. if (ack != VIRTIO_NET_CTRL_RX_ON) {
  969. print("vionetctrl: cmd = %d ack is ERR\n", cmd);
  970. error(Eio);
  971. }
  972.  
  973. return;
  974. }
  975.  
  976. static void
  977. vionetpromiscuous(void* arg, int on)
  978. {
  979. Ether* edev;
  980.  
  981. edev = arg;
  982. vionetctrl(edev, VIRTIO_NET_CTRL_RX_CMD_PROMISC, on);
  983.  
  984. return;
  985. }
  986.  
  987. static void
  988. vionetmulticast(void* arg, uchar*, int on)
  989. {
  990. Ether* edev;
  991.  
  992. edev = arg;
  993. vionetctrl(edev, VIRTIO_NET_CTRL_RX_CMD_ALLMULTI, on);
  994.  
  995. return;
  996. }
  997.  
  998. /*
  999. * Finds all virtio-net devices and list up in vionethead to vionettail.
  1000. * Do virtio-dev init and mkvqueue
  1001. */
  1002. static void
  1003. vionetpci(void)
  1004. {
  1005. Pcidev* p;
  1006. Vdev *vd;
  1007.  
  1008. print("vionetpci: in %d %d \n",
  1009. sizeof(Vnetreqhdr), sizeof(Vnetctrl));
  1010. for (p = nil; p = pcimatch(p, 0, 0);) {
  1011. if (p->vid != 0x1af4)
  1012. continue;
  1013. if ((p->did < 0x1000) || (p->did >= 0x1040))
  1014. continue;
  1015. if (p->rid != 0)
  1016. continue;
  1017. if (pcicfgr16(p, 0x2e) != 1 /* virtio-net subid */)
  1018. continue;
  1019. print("vionetpci: found device\n");
  1020. if ((vd = malloc(sizeof(*vd))) == nil) {
  1021. print("vionetpci(): cannnot allocate Vdev\n");
  1022. break;
  1023. }
  1024. print("vionetpci: vd alloced\n");
  1025.  
  1026. vd->port = p->mem[0].bar & ~0x1;
  1027. if (ioalloc(vd->port, p->mem[0].size, 0, "virtio") < 0) {
  1028. print("virtio: port %lux in use\n", vd->port);
  1029. free(vd);
  1030. continue;
  1031. }
  1032.  
  1033. vd->typ = 1 /* nic */;
  1034. vd->pci = p;
  1035.  
  1036. /* reset */
  1037. outb(vd->port + Status, 0);
  1038.  
  1039. /* set Acknowkedge and Driver */
  1040. print("vionetpci: Acknowledge and Driver to device\n");
  1041. outl(vd->port+Status, inb(vd->port+Status)|Acknowledge|Driver);
  1042. print("vionetpci: sent Acknowledge and Driver to device\n");
  1043.  
  1044. /* prepare vionet device */
  1045. print("vionetpci: call vionetinit()\n");
  1046. vionetinit(vd);
  1047. print("vionetpci: called vionetinit()\n");
  1048.  
  1049. print("vionetpnp: enable interrupt¥n");
  1050. //intrenable(vd->pci->intl, vionetinterrupt, vd, vd->pci->tbdf, "ethervirtio");
  1051. print("vionetpnp: enabled interrupt¥n");
  1052.  
  1053. /* done initialization */
  1054. print("vionetpnp: set status DriverOk\n");
  1055. outb(vd->port + Status, inb(vd->port + Status) | DriverOk);
  1056. print("vionetpnp: seted status DriverOk\n");
  1057.  
  1058. vd->next = nil;
  1059. if (vionethead == nil)
  1060. vionethead = vd;
  1061. else
  1062. vionettail->next = vd;
  1063. vionettail = vd;
  1064. print("inited : vd %p\n", vd);
  1065. print("inited : vd q0 %p\n", vd->queue[0]);
  1066. print("inited : vd q1 %p\n", vd->queue[1]);
  1067. }
  1068. print("vionetpci: out\n");
  1069. }
  1070.  
  1071. static int
  1072. vionetpnp(Ether* edev)
  1073. {
  1074. Vdev* vd;
  1075. static int done;
  1076.  
  1077. if (!done) {
  1078. vionetpci(); /* do initialize each device */
  1079. done = 1;
  1080. }
  1081.  
  1082. for (vd = vionethead; ; vd = vd->next) {
  1083. if (vd == nil)
  1084. return -1;
  1085. if (vd->active)
  1086. continue;
  1087. if (edev->port == 0 || edev->port == vd->port) {
  1088. vd->active = 1;
  1089. break;
  1090. }
  1091. }
  1092.  
  1093. if (vd == nil)
  1094. return -1;
  1095.  
  1096. edev->ctlr = vd;
  1097. edev->port = vd->port;
  1098. edev->irq = vd->pci->intl;
  1099. edev->tbdf = vd->pci->tbdf;
  1100. edev->mbps = 1000;
  1101.  
  1102. print("vionetpnp: edev %p\n", edev);
  1103. print("vionetpnp: vd %p\n", vd);
  1104. print("vionetpnp: call vionetinit1\n");
  1105. vionetinit1(edev, vd);
  1106. print("vionetpnp: called vionetinit1\n");
  1107. /*
  1108. * set handler functions
  1109. */
  1110. edev->attach = vionetattach;
  1111. edev->transmit = vionettransmit;
  1112. edev->interrupt = vionetinterrupt;
  1113. edev->ifstat = vionetifstat;
  1114. edev->shutdown = vionetshutdown;
  1115. edev->ctl = vionetctl;
  1116. edev->arg = edev;
  1117. /*
  1118. edev->promiscuous = vionetpromiscuous;
  1119. edev->multicast = vionetmulticast;
  1120. */
  1121.  
  1122. print("vionetpnp: out\n");
  1123. return 0;
  1124. }
  1125.  
  1126. void
  1127. ethervirtiolink(void)
  1128. {
  1129. addethercard("virtio", vionetpnp);
  1130. }
Add Comment
Please, Sign In to add comment