1 /******************************************************************************
2 * Copyright (c) 2011, 2013 IBM Corporation
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
10 * IBM Corporation - initial implementation
11 *****************************************************************************/
19 #include "libhvcall.h"
24 #define dprintf(_x ...) do { printf(_x); } while(0)
26 #define dprintf(_x ...)
29 /* *** WARNING: We pass our addresses as-is as DMA addresses,
30 * we -do- rely on the forth code to have enabled TCE bypass
33 #define vaddr_to_dma(vaddr) ((uint64_t)vaddr)
35 struct ibmveth_buf_desc_fields {
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
45 union ibmveth_buf_desc {
47 struct ibmveth_buf_desc_fields fields;
50 struct ibmveth_rx_q_entry {
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
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;
70 #define RX_QUEUE_SIZE 256
71 #define RX_BUF_SIZE 2048
72 #define RX_BUF_MULT (RX_BUF_SIZE >> 3)
74 static struct ibmveth_rx_q_entry *rx_queue;
76 static inline uint64_t *veth_get_rx_buf(unsigned int i)
78 return &rx_bufs_aligned[i * RX_BUF_MULT];
81 static int veth_init(net_driver_t *driver)
84 union ibmveth_buf_desc rxq_desc;
85 unsigned long rx_queue_len = sizeof(struct ibmveth_rx_q_entry) *
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]);
97 if (driver->running != 0)
100 mac_addr = (char *)driver->mac_addr;
101 cur_rx_toggle = IBMVETH_RXQ_TOGGLE;
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");
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;
115 rc = h_register_logical_lan(driver->reg,
116 vaddr_to_dma(buffer_list),
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);
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);
138 SLOF_free_mem(buffer_list, 8192);
140 SLOF_free_mem(rx_queue, rx_queue_len);
142 SLOF_free_mem(rx_bufs, 2048 * RX_QUEUE_SIZE + 4);
146 static int veth_term(net_driver_t *driver)
148 dprintf("veth_term()\n");
150 if (driver->running == 0)
153 h_free_logical_lan(driver->reg);
156 SLOF_free_mem(buffer_list, 8192);
158 SLOF_free_mem(rx_queue, sizeof(struct ibmveth_rx_q_entry) * RX_QUEUE_SIZE);
160 SLOF_free_mem(rx_bufs, 2048 * RX_QUEUE_SIZE + 4);
167 static int veth_receive(char *f_buffer_pc, int f_len_i, net_driver_t *driver)
171 dprintf("veth_receive()\n");
174 struct ibmveth_rx_q_entry *desc = &rx_queue[cur_rx_index];
175 union ibmveth_buf_desc bdesc;
178 buf = (void *)desc->correlator;
180 if ((desc->flags_off & IBMVETH_RXQ_TOGGLE) != cur_rx_toggle)
183 if (!(desc->flags_off & IBMVETH_RXQ_VALID))
185 if (desc->length > f_len_i) {
186 printf("veth: Dropping too big packet [%d bytes]\n",
191 packet = desc->length;
193 buf + (desc->flags_off & IBMVETH_RXQ_OFF_MASK), packet);
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);
199 cur_rx_index = (cur_rx_index + 1) % RX_QUEUE_SIZE;
200 if (cur_rx_index == 0)
201 cur_rx_toggle ^= IBMVETH_RXQ_TOGGLE;
207 static int veth_xmit(char *f_buffer_pc, int f_len_i, net_driver_t *driver)
209 union ibmveth_buf_desc tx_desc;
212 dprintf("veth_xmit(packet at %p, %d bytes)\n", f_buffer_pc, f_len_i);
214 tx_desc.fields.address = vaddr_to_dma(f_buffer_pc);
215 tx_desc.fields.flags_len = IBMVETH_BUF_VALID | f_len_i;
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);
226 net_driver_t *libveth_open(char *mac_addr, int mac_len, char *reg, int reg_len)
228 net_driver_t *driver;
230 driver = SLOF_alloc_mem(sizeof(*driver));
232 printf("Unable to allocate veth driver\n");
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)
239 memcpy(driver->mac_addr, mac_addr, 6);
240 driver->reg = *(uint32_t *)reg;
243 if (veth_init(driver)) {
244 SLOF_free_mem(driver, sizeof(*driver));
251 void libveth_close(net_driver_t *driver)
255 SLOF_free_mem(driver, sizeof(*driver));
259 int libveth_read(char *buf, int len, net_driver_t *driver)
262 return veth_receive(buf, len, driver);
267 int libveth_write(char *buf, int len, net_driver_t *driver)
270 return veth_xmit(buf, len, driver);