1#include "vmkitmon.h"
2#include "pci.h"
3#include "pci_devices.h"
4#include "pci_vmkitmon_eth.h"
5#include "guest.h"
6#include "string.h"
7#include "benchmark.h"
8#include <pci/devids.h>
9#include <net_queue_manager/net_queue_manager.h>
10#include <if/net_queue_manager_defs.h>
11
12#define PCI_ETHERNET_IRQ 11
13#define INVALID         0xffffffff
14#define PCI_HEADER_MEM_ROM_BASE_REGISTER 0xc
15
16#define DRIVER_RECEIVE_BUFFERS 256
17#define DRIVER_TRANSMIT_BUFFER 256
18
19int global_packet_in_count = 0;
20
21static uint8_t guest_mac[] = { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF}; //The mac address presented to virt. linux
22static uint8_t host_mac[] = { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xBF}; //The mac address presented to barrelfish
23static uint64_t assumed_queue_id = 0;
24static struct pci_device *the_pci_vmkitmon_eth;
25
26// Data-structure to map sent buffer slots back to application slots
27struct pbuf_desc {
28    void *opaque;
29};
30static struct pbuf_desc pbuf_list_tx[DRIVER_TRANSMIT_BUFFER];
31
32// tx_index = head, tx_bufptr = tail
33static uint32_t ether_transmit_index = 0, ether_transmit_bufptr = 0;
34
35// rx_index = head, rx_bufptr = tail
36static uint32_t receive_index = 0, receive_bufptr = 0;
37static uint32_t receive_free = 0;
38
39struct rx_buffer {
40    uint64_t paddr;
41    void *vaddr;
42    void *opaque;
43};
44static struct rx_buffer rx_buffer_ring[DRIVER_RECEIVE_BUFFERS];
45
46static void generate_interrupt(struct pci_device *dev){
47	struct pci_vmkitmon_eth * h = dev->state;
48	h->mmio_register[PCI_VMKITMON_ETH_STATUS] |= PCI_VMKITMON_ETH_IRQST;
49	lpc_pic_assert_irq(dev->lpc, dev->irq);
50}
51
52static void confspace_write(struct pci_device *dev,
53                            union pci_config_address_word addr,
54                            enum opsize size, uint32_t val)
55{
56	VMKITMON_ETH_DEBUG("pci_vmkitmon_eth confspace_write addr: 0x%x, val: 0x%x\n", addr.d.doubleword, val);
57	struct pci_vmkitmon_eth *h = dev->state;
58	if(4 <= addr.d.doubleword && addr.d.doubleword <= 9 && val == INVALID){
59		//caller wants to figure out bar size
60		val = ~h->pci_device->bars[addr.d.doubleword - 4].bytes + 1; //~0x100000 + 1
61		VMKITMON_ETH_DEBUG("pci_vmkitmon_eth writing bar %d size. 0x%x\n", addr.d.doubleword-4, val);
62	}
63	if(addr.d.doubleword == 1){
64		//status register is clear by write 1
65		val = (val & 0xffff) | (h->pci_header[addr.d.doubleword] & ~val)<<16;
66	}
67	h->pci_header[addr.d.doubleword] = val;
68}
69
70static void confspace_read(struct pci_device *dev,
71                           union pci_config_address_word addr,
72                           enum opsize size, uint32_t *val)
73{
74	VMKITMON_ETH_DEBUG("confspace_read addr: 0x%x, ",addr.d.doubleword);
75    struct pci_vmkitmon_eth *h = dev->state;
76
77    if(addr.d.fnct_nr != 0) {
78        *val = INVALID;
79    } else {
80    	if(addr.d.doubleword == PCI_HEADER_MEM_ROM_BASE_REGISTER) {
81    		//we dont support a rom, return always 0
82    		*val = 0;
83    	} else if(addr.d.doubleword < 0x40) {
84			*val = h->pci_header[addr.d.doubleword];
85		} else {
86			*val = INVALID;
87		}
88    }
89
90    VMKITMON_ETH_DEBUG(" val: 0x%x\n", *val);
91}
92
93static void get_mac_address_fn(uint8_t* mac)
94{
95    memcpy(mac, &host_mac, 6);
96}
97
98#if defined(VMKITMON_ETH_DEBUG_SWITCH)
99static void dumpRegion(uint8_t *start){
100	printf("-- dump starting from 0x%lx --\n", (uint64_t)start);
101	for(int i=0; i<64;i++){
102		printf("0x%04x: ", i*16);
103		for(int j=0; j<16; j++){
104			printf("%02x ", *( (start) + (i*16 + j)));
105		}
106		printf("\n");
107	}
108	printf("-- dump finished --\n");
109}
110#endif
111
112static errval_t transmit_pbuf_list_fn(struct driver_buffer *buffers, size_t size) {
113	struct pci_vmkitmon_eth *h = the_pci_vmkitmon_eth->state;
114	int i;
115	uint64_t paddr;
116
117	record_packet_receive_from_bf();
118
119    VMKITMON_ETH_DEBUG("transmit_pbuf_list_fn, no_pbufs: 0x%lx\n", size);
120
121	struct pci_vmkitmon_eth_rxdesc * first_rx = (struct pci_vmkitmon_eth_rxdesc *) guest_to_host( h->mmio_register[PCI_VMKITMON_ETH_RXDESC_ADR] );
122	uint32_t rxdesc_len = h->mmio_register[PCI_VMKITMON_ETH_RXDESC_ADR];
123
124	int transmitted = 0;
125	for (i = 0; i < size; i++) {
126        struct driver_buffer *buffer = &buffers[i];
127
128		paddr = buffer->pa;
129		VMKITMON_ETH_DEBUG("paddr: 0x%lx, len: 0x%lx\n", paddr, buffer->len);
130#if defined(VMKITMON_ETH_DEBUG_SWITCH)
131		dumpRegion(buffer->va);
132#endif
133
134		for(int j = 0; j <= rxdesc_len/sizeof(struct pci_vmkitmon_eth_rxdesc); j++){
135			struct pci_vmkitmon_eth_rxdesc * cur_rx =first_rx + j;
136			if(cur_rx->len == 0 && cur_rx->addr != 0){
137				void *hv_addr = (void *)guest_to_host(cur_rx->addr);
138				memcpy(hv_addr, buffer->va, buffer->len);
139				cur_rx->len = buffer->len;
140				VMKITMON_ETH_DEBUG("Used rxdesc %d to transmit\n", j);
141				transmitted = 1;
142
143                pbuf_list_tx[ether_transmit_index].opaque = buffer->opaque;
144                ether_transmit_index = (ether_transmit_index + 1) % DRIVER_TRANSMIT_BUFFER;
145
146				break;
147			}
148		}
149	}
150
151	if(transmitted){
152		generate_interrupt(the_pci_vmkitmon_eth);
153	}
154
155	return SYS_ERR_OK;
156}
157
158static uint64_t find_tx_free_slot_count_fn(void) {
159	//only called once at beginning & looks fine (returns 256)
160    uint64_t nr_free;
161    if (ether_transmit_index >= ether_transmit_bufptr) {
162        nr_free = DRIVER_TRANSMIT_BUFFER -
163            ((ether_transmit_index - ether_transmit_bufptr) %
164                DRIVER_TRANSMIT_BUFFER);
165    } else {
166        nr_free = DRIVER_TRANSMIT_BUFFER -
167            ((ether_transmit_bufptr - ether_transmit_index) %
168            DRIVER_TRANSMIT_BUFFER);
169    }
170    //printf("find_tx_free_slot_count_fn: %lu, case1?: %d\n", nr_free, ether_transmit_index >= ether_transmit_bufptr);
171    return nr_free;
172}
173
174static bool handle_free_TX_slot_fn(void) {
175	VMKITMON_ETH_DEBUG("handle_free_TX_slot_fn\n");
176
177    if(ether_transmit_bufptr == ether_transmit_index) {
178        return false;
179    }
180
181    handle_tx_done(pbuf_list_tx[ether_transmit_bufptr].opaque);
182
183    ether_transmit_bufptr = (ether_transmit_bufptr + 1) % DRIVER_TRANSMIT_BUFFER;
184    //netbench_record_event_simple(bm, RE_TX_DONE, rdtsc());
185	return true;
186}
187
188static void transmit_pending_packets(struct pci_vmkitmon_eth * h){
189	VMKITMON_ETH_DEBUG("transmit_pending_packets\n");
190	uint32_t rxdesc_len = h->mmio_register[PCI_VMKITMON_ETH_TXDESC_LEN];
191	struct pci_vmkitmon_eth_txdesc * first_tx = (struct pci_vmkitmon_eth_txdesc *) guest_to_host( h->mmio_register[PCI_VMKITMON_ETH_TXDESC_ADR] );
192	for(int i=0; i <= rxdesc_len/sizeof(struct pci_vmkitmon_eth_rxdesc); i++){
193		struct pci_vmkitmon_eth_txdesc * cur_tx =first_tx + i;
194		if(cur_tx->len != 0 && cur_tx->addr != 0){
195			void *hv_addr = (void *)guest_to_host(cur_tx->addr);
196			//VMKITMON_ETH_DEBUG("Sending packet at txdesc %d, addr: 0x%x, len: 0x%x\n", i, cur_tx->addr, cur_tx->len);
197			//printf("Sending packet at txdesc %d, addr: 0x%x, len: 0x%x\n", i, cur_tx->addr, cur_tx->len);
198
199            if(receive_free == 0) {
200                VMKITMON_ETH_DEBUG("Could not deliver packet, no receive buffer available. Drop packet.\n");
201                printf("Could not deliver packet, no receive buffer available. Drop packet.\n");
202            } else {
203                struct driver_rx_buffer buf;
204                memcpy(rx_buffer_ring[receive_bufptr].vaddr, hv_addr, cur_tx->len);
205                //printf("got packet with len: %d\n",cur_tx->len);
206                if(cur_tx->len == 185){
207                	print_bench_stats();
208                } else {
209					record_packet_transmit_to_bf();
210                }
211                buf.opaque = rx_buffer_ring[receive_bufptr].opaque;
212                buf.len = cur_tx->len;
213                process_received_packet(&buf, 1, 0);
214                /*
215                if(*(unsigned char *)hv_addr == 0xaa) {
216                    //printf("packet %d delivered to barrelfish\n", ++global_packet_in_count);
217                    if(0) dumpRegion(hv_addr);
218                    unsigned char *xid = hv_addr + 42;
219                    if(*xid == 0 && *(xid + 1) == 0){
220						printf("XID: 0x%02x%02x%02x%02x\n", *xid, *(xid + 1), *(xid + 2), *(xid + 3));
221                    	//dumpRegion(hv_addr);
222                    }
223                } */
224                receive_bufptr = (receive_bufptr + 1) % DRIVER_RECEIVE_BUFFERS;
225                --receive_free;
226            }
227			memset(hv_addr, 0xBF, cur_tx->len);
228            cur_tx->len = 0;
229		}
230	}
231}
232
233static errval_t rx_register_buffer_fn(uint64_t paddr, void *vaddr, void *opaque) {
234    VMKITMON_ETH_DEBUG("rx_register_buffer_fn called\n");
235
236    rx_buffer_ring[receive_index].paddr = paddr;
237    rx_buffer_ring[receive_index].vaddr = vaddr;
238    rx_buffer_ring[receive_index].opaque = opaque;
239
240    receive_index = (receive_index + 1) % DRIVER_RECEIVE_BUFFERS;
241    receive_free++;
242    return SYS_ERR_OK;
243}
244
245static uint64_t rx_find_free_slot_count_fn(void) {
246	uint64_t nr_free;
247	if (receive_index >= receive_bufptr) {
248		nr_free = DRIVER_RECEIVE_BUFFERS -
249			((receive_index - receive_bufptr) %
250				DRIVER_RECEIVE_BUFFERS);
251	} else {
252		nr_free = DRIVER_RECEIVE_BUFFERS -
253			((receive_bufptr - receive_index) %
254			  DRIVER_RECEIVE_BUFFERS);
255	}
256	VMKITMON_ETH_DEBUG("rx_find_free_slot_count_fn called, returning %lu\n", nr_free);
257    return nr_free;
258}
259
260static void mem_write(struct pci_device *dev, uint32_t addr, int bar, uint32_t val){
261	struct pci_vmkitmon_eth *h = dev->state;
262	VMKITMON_ETH_DEBUG("mem_write addr: 0x%x,  bar: %d, val: 0x%x, irq: %d\n",addr, bar, val, dev->irq );
263	switch(addr) {
264	case PCI_VMKITMON_ETH_STATUS:
265		break;
266	case PCI_VMKITMON_ETH_CONTROL:
267		if( val & PCI_VMKITMON_ETH_RSTIRQ )
268			h->mmio_register[PCI_VMKITMON_ETH_STATUS] &= ~PCI_VMKITMON_ETH_IRQST;
269		if( val & PCI_VMKITMON_ETH_TXMIT ) {
270			VMKITMON_ETH_DEBUG("Transmitting packet. guest-phys packet base address: 0x%x, packet-len: 0x%x\n",h->mmio_register[PCI_VMKITMON_ETH_TXDESC_ADR], h->mmio_register[PCI_VMKITMON_ETH_TXDESC_LEN]);
271			transmit_pending_packets(h);
272        }
273		if( val & PCI_VMKITMON_ETH_IFUP) {
274			VMKITMON_ETH_DEBUG("Interface up, registering\n");
275			// register to queue_manager
276			ethersrv_init("vmkitmon_eth",
277                          assumed_queue_id,
278                          get_mac_address_fn,
279                          NULL,
280                          transmit_pbuf_list_fn,
281                          find_tx_free_slot_count_fn,
282                          handle_free_TX_slot_fn,
283                          2048, //                      rx_buffer_size,
284                          rx_register_buffer_fn,
285                          rx_find_free_slot_count_fn
286                          );
287
288		}
289		break;
290	default:
291		h->mmio_register[addr] = val;
292		break;
293	}
294}
295
296static void mem_read(struct pci_device *dev, uint32_t addr, int bar, uint32_t *val){
297	struct pci_vmkitmon_eth *h = (struct pci_vmkitmon_eth *) dev->state;
298	if(addr != 0) VMKITMON_ETH_DEBUG("mem_read addr: 0x%x,  bar: %d, asserting irq: %d\n",addr, bar, dev->irq);
299	switch(addr){
300	case PCI_VMKITMON_ETH_MAC_LOW:
301		memcpy(val, guest_mac, 4);
302		break;
303	case PCI_VMKITMON_ETH_MAC_HIGH:
304		memcpy(val, guest_mac+4, 2);
305		break;
306	default:
307		*val = h->mmio_register[addr];
308	}
309}
310
311
312struct pci_device *pci_vmkitmon_eth_new(struct lpc *lpc, struct guest *g) {
313	struct pci_device *dev = calloc(1, sizeof(struct pci_device));
314	struct pci_vmkitmon_eth *host = calloc(1, sizeof(struct pci_vmkitmon_eth));
315	host->pci_device = dev;
316
317	//initialize device
318	dev->confspace_write = confspace_write;
319	dev->confspace_read = confspace_read;
320	dev->mem_read = mem_read;
321	dev->mem_write = mem_write;
322	dev->state = host;
323	dev->irq = PCI_ETHERNET_IRQ;
324	dev->lpc = lpc;
325
326	pci_hdr0_mem_t *ph = &host->ph;
327	pci_hdr0_mem_initialize(ph, (mackerel_addr_t) host->pci_header);
328
329	pci_hdr0_mem_vendor_id_wr(ph, PCI_VENDOR_FISH);
330	pci_hdr0_mem_device_id_wr(ph, PCI_VMKITMON_ETH_DEVID);
331	pci_hdr0_mem_class_code_clss_wrf(ph, PCI_CLASS_ETHERNET);
332
333	//The next line could be: pci_hdr0_mem_int_line_wr(ph, PCI_ETHERNET_IRQ);
334	//but the register is defined read only...
335	host->pci_header[0xf] = 1<<8 | PCI_ETHERNET_IRQ;
336
337
338	//Figure out a nice address, for the moment, make sure you dont go over 0xce000000
339	// and stay close beyond (thats the point where the ixgbe is mapped).
340	host->mem_guest_paddr = 0xcb000000;
341	dev->bars[0].paddr = host->mem_guest_paddr;
342	dev->bars[0].bytes = 0x100000; //1 MB
343
344	//Write BAR0 into pci header
345	pci_hdr0_mem_bars_wr(ph, 0, host->mem_guest_paddr);
346
347	the_pci_vmkitmon_eth = dev;
348	return dev;
349}
350