Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / SLOF / lib / libveth / veth.c
1 /******************************************************************************
2  * Copyright (c) 2011, 2013 IBM Corporation
3  * All rights reserved.
4  * This program and the accompanying materials
5  * are made available under the terms of the BSD License
6  * which accompanies this distribution, and is available at
7  * http://www.opensource.org/licenses/bsd-license.php
8  *
9  * Contributors:
10  *     IBM Corporation - initial implementation
11  *****************************************************************************/
12
13 #include <stdlib.h>
14 #include <stdio.h>
15 #include <stdint.h>
16 #include <string.h>
17 #include <helpers.h>
18 #include "veth.h"
19 #include "libhvcall.h"
20
21 #undef VETH_DEBUG
22 //#define VETH_DEBUG
23 #ifdef VETH_DEBUG
24 #define dprintf(_x ...) do { printf(_x); } while(0)
25 #else
26 #define dprintf(_x ...)
27 #endif
28
29 /* *** WARNING: We pass our addresses as-is as DMA addresses,
30  *     we -do- rely on the forth code to have enabled TCE bypass
31  *     on our device !
32  */
33 #define vaddr_to_dma(vaddr)     ((uint64_t)vaddr)
34
35 struct ibmveth_buf_desc_fields {
36         uint32_t flags_len;
37 #define IBMVETH_BUF_VALID       0x80000000
38 #define IBMVETH_BUF_TOGGLE      0x40000000
39 #define IBMVETH_BUF_NO_CSUM     0x02000000
40 #define IBMVETH_BUF_CSUM_GOOD   0x01000000
41 #define IBMVETH_BUF_LEN_MASK    0x00FFFFFF
42         uint32_t address;
43 };
44
45 union ibmveth_buf_desc {
46         uint64_t desc;
47         struct ibmveth_buf_desc_fields fields;
48 };
49
50 struct ibmveth_rx_q_entry {
51         uint32_t flags_off;
52 #define IBMVETH_RXQ_TOGGLE              0x80000000
53 #define IBMVETH_RXQ_TOGGLE_SHIFT        31
54 #define IBMVETH_RXQ_VALID               0x40000000
55 #define IBMVETH_RXQ_NO_CSUM             0x02000000
56 #define IBMVETH_RXQ_CSUM_GOOD           0x01000000
57 #define IBMVETH_RXQ_OFF_MASK            0x0000FFFF
58
59         uint32_t length;
60         uint64_t correlator;
61 };
62
63 static void *buffer_list; 
64 static void *filter_list; 
65 static uint64_t *rx_bufs;
66 static uint64_t *rx_bufs_aligned;
67 static uint32_t cur_rx_toggle;
68 static uint32_t cur_rx_index;
69
70 #define RX_QUEUE_SIZE   256
71 #define RX_BUF_SIZE     2048
72 #define RX_BUF_MULT     (RX_BUF_SIZE >> 3)
73
74 static struct ibmveth_rx_q_entry *rx_queue;
75
76 static inline uint64_t *veth_get_rx_buf(unsigned int i)
77 {
78         return &rx_bufs_aligned[i * RX_BUF_MULT];
79 }
80
81 static int veth_init(net_driver_t *driver)
82 {
83         char *mac_addr;
84         union ibmveth_buf_desc rxq_desc;
85         unsigned long rx_queue_len = sizeof(struct ibmveth_rx_q_entry) *
86                 RX_QUEUE_SIZE;
87         unsigned int i;
88         long rc;
89
90         if (!driver)
91                 return -1;
92
93         dprintf("veth_init(%02x:%02x:%02x:%02x:%02x:%02x)\n",
94                 mac_addr[0], mac_addr[1], mac_addr[2],
95                 mac_addr[3], mac_addr[4], mac_addr[5]);
96
97         if (driver->running != 0)
98                 return 0;
99
100         mac_addr = (char *)driver->mac_addr;
101         cur_rx_toggle = IBMVETH_RXQ_TOGGLE;
102         cur_rx_index = 0;
103         buffer_list = SLOF_alloc_mem_aligned(8192, 4096);
104         filter_list = buffer_list + 4096;
105         rx_queue = SLOF_alloc_mem_aligned(rx_queue_len, 16);
106         rx_bufs = SLOF_alloc_mem(2048 * RX_QUEUE_SIZE + 4);
107         if (!buffer_list || !filter_list || !rx_queue || !rx_bufs) {
108                 printf("veth: Failed to allocate memory !\n");
109                 goto fail;
110         }
111         rx_bufs_aligned = (uint64_t *)(((uint64_t)rx_bufs | 3) + 1);
112         rxq_desc.fields.address = vaddr_to_dma(rx_queue);
113         rxq_desc.fields.flags_len = IBMVETH_BUF_VALID | rx_queue_len;
114
115         rc = h_register_logical_lan(driver->reg,
116                                     vaddr_to_dma(buffer_list),
117                                     rxq_desc.desc,
118                                     vaddr_to_dma(filter_list),
119                                     (*(uint64_t *)mac_addr) >> 16);
120         if (rc != H_SUCCESS) {
121                 printf("veth: Error %ld registering interface !\n", rc);
122                 goto fail;
123         }
124         for (i = 0; i < RX_QUEUE_SIZE; i++) {
125                 uint64_t *buf = veth_get_rx_buf(i);
126                 union ibmveth_buf_desc desc;
127                 *buf = (uint64_t)buf;
128                 desc.fields.address = vaddr_to_dma(buf);
129                 desc.fields.flags_len = IBMVETH_BUF_VALID | RX_BUF_SIZE;
130                 h_add_logical_lan_buffer(driver->reg, desc.desc);
131         }
132
133         driver->running = 1;
134
135         return 0;
136  fail:
137         if (buffer_list)
138                 SLOF_free_mem(buffer_list, 8192);
139         if (rx_queue)
140                 SLOF_free_mem(rx_queue, rx_queue_len);
141         if (rx_bufs)
142                 SLOF_free_mem(rx_bufs, 2048 * RX_QUEUE_SIZE + 4);
143         return -1;
144 }
145
146 static int veth_term(net_driver_t *driver)
147 {
148         dprintf("veth_term()\n");
149
150         if (driver->running == 0)
151                 return 0;
152
153         h_free_logical_lan(driver->reg);
154
155         if (buffer_list)
156                 SLOF_free_mem(buffer_list, 8192);
157         if (rx_queue)
158                 SLOF_free_mem(rx_queue, sizeof(struct ibmveth_rx_q_entry) * RX_QUEUE_SIZE);
159         if (rx_bufs)
160                 SLOF_free_mem(rx_bufs, 2048 * RX_QUEUE_SIZE + 4);
161
162         driver->running = 0;
163
164         return 0;
165 }
166
167 static int veth_receive(char *f_buffer_pc, int f_len_i, net_driver_t *driver)
168 {
169         int packet = 0;
170
171         dprintf("veth_receive()\n");
172
173         while(!packet) {
174                 struct ibmveth_rx_q_entry *desc = &rx_queue[cur_rx_index];
175                 union ibmveth_buf_desc bdesc;
176                 void *buf;
177
178                 buf = (void *)desc->correlator;
179
180                 if ((desc->flags_off & IBMVETH_RXQ_TOGGLE) != cur_rx_toggle)
181                         break;
182
183                 if (!(desc->flags_off & IBMVETH_RXQ_VALID))
184                         goto recycle;
185                 if (desc->length > f_len_i) {
186                         printf("veth: Dropping too big packet [%d bytes]\n",
187                                desc->length);
188                         goto recycle;
189                 }
190
191                 packet = desc->length;
192                 memcpy(f_buffer_pc,
193                        buf + (desc->flags_off & IBMVETH_RXQ_OFF_MASK), packet);
194         recycle:
195                 bdesc.fields.address = vaddr_to_dma(buf);
196                 bdesc.fields.flags_len = IBMVETH_BUF_VALID | RX_BUF_SIZE;
197                 h_add_logical_lan_buffer(driver->reg, bdesc.desc);
198
199                 cur_rx_index = (cur_rx_index + 1) % RX_QUEUE_SIZE;
200                 if (cur_rx_index == 0)
201                         cur_rx_toggle ^= IBMVETH_RXQ_TOGGLE;
202         }
203
204         return packet;
205 }
206
207 static int veth_xmit(char *f_buffer_pc, int f_len_i, net_driver_t *driver)
208 {
209         union ibmveth_buf_desc tx_desc;
210         long rc;
211
212         dprintf("veth_xmit(packet at %p, %d bytes)\n", f_buffer_pc, f_len_i);
213
214         tx_desc.fields.address = vaddr_to_dma(f_buffer_pc);
215         tx_desc.fields.flags_len = IBMVETH_BUF_VALID | f_len_i;
216
217         rc = hv_send_logical_lan(driver->reg, tx_desc.desc, 0, 0, 0, 0, 0);
218         if (rc != H_SUCCESS) {
219                 printf("veth: Error %ld sending packet !\n", rc);
220                 return -1;
221         }
222
223         return f_len_i;
224 }
225
226 net_driver_t *libveth_open(char *mac_addr, int mac_len, char *reg, int reg_len)
227 {
228         net_driver_t *driver;
229
230         driver = SLOF_alloc_mem(sizeof(*driver));
231         if (!driver) {
232                 printf("Unable to allocate veth driver\n");
233                 return NULL;
234         }
235
236         /* veth uses a 8-byte wide property instead of 6-byte wide MACs */
237         if ((mac_len == 8) && (mac_addr[0] == 0) && mac_addr[1] == 0)
238                 mac_addr += 2;
239         memcpy(driver->mac_addr, mac_addr, 6);
240         driver->reg = *(uint32_t *)reg;
241         driver->running = 0;
242
243         if (veth_init(driver)) {
244                 SLOF_free_mem(driver, sizeof(*driver));
245                 return NULL;
246         }
247
248         return driver;
249 }
250
251 void libveth_close(net_driver_t *driver)
252 {
253         if (driver) {
254                 veth_term(driver);
255                 SLOF_free_mem(driver, sizeof(*driver));
256         }
257 }
258
259 int libveth_read(char *buf, int len, net_driver_t *driver)
260 {
261         if (buf)
262                 return veth_receive(buf, len, driver);
263
264         return -1;
265 }
266
267 int libveth_write(char *buf, int len, net_driver_t *driver)
268 {
269         if (buf)
270                 return veth_xmit(buf, len, driver);
271
272         return -1;
273 }