2 * QEMU rocker switch emulation - front-panel ports
4 * Copyright (c) 2014 Scott Feldman <sfeldma@gmail.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
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.
17 #include "qemu/osdep.h"
18 #include "qapi/qapi-types-rocker.h"
20 #include "rocker_hw.h"
21 #include "rocker_fp.h"
22 #include "rocker_world.h"
44 char *fp_port_get_name(FpPort
*port
)
49 bool fp_port_get_link_up(FpPort
*port
)
51 return !qemu_get_queue(port
->nic
)->link_down
;
54 RockerPort
*fp_port_get_info(FpPort
*port
)
56 RockerPort
*value
= g_malloc0(sizeof(*value
));
58 value
->name
= g_strdup(port
->name
);
59 value
->enabled
= port
->enabled
;
60 value
->link_up
= fp_port_get_link_up(port
);
61 value
->speed
= port
->speed
;
62 value
->duplex
= port
->duplex
;
63 value
->autoneg
= port
->autoneg
;
67 void fp_port_get_macaddr(FpPort
*port
, MACAddr
*macaddr
)
69 memcpy(macaddr
->a
, port
->conf
.macaddr
.a
, sizeof(macaddr
->a
));
72 void fp_port_set_macaddr(FpPort
*port
, MACAddr
*macaddr
)
74 /* XXX TODO implement and test setting mac addr
75 * XXX memcpy(port->conf.macaddr.a, macaddr.a, sizeof(port->conf.macaddr.a));
79 uint8_t fp_port_get_learning(FpPort
*port
)
81 return port
->learning
;
84 void fp_port_set_learning(FpPort
*port
, uint8_t learning
)
86 port
->learning
= learning
;
89 int fp_port_get_settings(FpPort
*port
, uint32_t *speed
,
90 uint8_t *duplex
, uint8_t *autoneg
)
93 *duplex
= port
->duplex
;
94 *autoneg
= port
->autoneg
;
99 int fp_port_set_settings(FpPort
*port
, uint32_t speed
,
100 uint8_t duplex
, uint8_t autoneg
)
102 /* XXX validate inputs */
105 port
->duplex
= duplex
;
106 port
->autoneg
= autoneg
;
111 bool fp_port_from_pport(uint32_t pport
, uint32_t *port
)
113 if (pport
< 1 || pport
> ROCKER_FP_PORTS_MAX
) {
120 int fp_port_eg(FpPort
*port
, const struct iovec
*iov
, int iovcnt
)
122 NetClientState
*nc
= qemu_get_queue(port
->nic
);
125 qemu_sendv_packet(nc
, iov
, iovcnt
);
131 static ssize_t
fp_port_receive_iov(NetClientState
*nc
, const struct iovec
*iov
,
134 FpPort
*port
= qemu_get_nic_opaque(nc
);
136 /* If the port is disabled, we want to drop this pkt
137 * now rather than queueing it for later. We don't want
138 * any stale pkts getting into the device when the port
139 * transitions to enabled.
142 if (!port
->enabled
) {
146 return world_ingress(port
->world
, port
->pport
, iov
, iovcnt
);
149 static ssize_t
fp_port_receive(NetClientState
*nc
, const uint8_t *buf
,
152 const struct iovec iov
= {
153 .iov_base
= (uint8_t *)buf
,
157 return fp_port_receive_iov(nc
, &iov
, 1);
160 static void fp_port_cleanup(NetClientState
*nc
)
164 static void fp_port_set_link_status(NetClientState
*nc
)
166 FpPort
*port
= qemu_get_nic_opaque(nc
);
168 rocker_event_link_changed(port
->r
, port
->pport
, !nc
->link_down
);
171 static NetClientInfo fp_port_info
= {
172 .type
= NET_CLIENT_DRIVER_NIC
,
173 .size
= sizeof(NICState
),
174 .receive
= fp_port_receive
,
175 .receive_iov
= fp_port_receive_iov
,
176 .cleanup
= fp_port_cleanup
,
177 .link_status_changed
= fp_port_set_link_status
,
180 World
*fp_port_get_world(FpPort
*port
)
185 void fp_port_set_world(FpPort
*port
, World
*world
)
187 DPRINTF("port %d setting world \"%s\"\n", port
->index
, world_name(world
));
191 bool fp_port_check_world(FpPort
*port
, World
*world
)
193 return port
->world
== world
;
196 bool fp_port_enabled(FpPort
*port
)
198 return port
->enabled
;
201 static void fp_port_set_link(FpPort
*port
, bool up
)
203 NetClientState
*nc
= qemu_get_queue(port
->nic
);
205 if (up
== nc
->link_down
) {
207 nc
->info
->link_status_changed(nc
);
211 void fp_port_enable(FpPort
*port
)
213 fp_port_set_link(port
, true);
214 port
->enabled
= true;
215 DPRINTF("port %d enabled\n", port
->index
);
218 void fp_port_disable(FpPort
*port
)
220 port
->enabled
= false;
221 fp_port_set_link(port
, false);
222 DPRINTF("port %d disabled\n", port
->index
);
225 FpPort
*fp_port_alloc(Rocker
*r
, char *sw_name
,
226 MACAddr
*start_mac
, unsigned int index
,
229 FpPort
*port
= g_new0(FpPort
, 1);
233 port
->pport
= index
+ 1;
235 /* front-panel switch port names are 1-based */
237 port
->name
= g_strdup_printf("%sp%d", sw_name
, port
->pport
);
239 memcpy(port
->conf
.macaddr
.a
, start_mac
, sizeof(port
->conf
.macaddr
.a
));
240 port
->conf
.macaddr
.a
[5] += index
;
241 port
->conf
.bootindex
= -1;
242 port
->conf
.peers
= *peers
;
244 port
->nic
= qemu_new_nic(&fp_port_info
, &port
->conf
, sw_name
, NULL
,
245 &DEVICE(r
)->mem_reentrancy_guard
, port
);
246 qemu_format_nic_info_str(qemu_get_queue(port
->nic
),
247 port
->conf
.macaddr
.a
);
254 void fp_port_free(FpPort
*port
)
256 qemu_del_nic(port
->nic
);
261 void fp_port_reset(FpPort
*port
)
263 fp_port_disable(port
);
264 port
->speed
= 10000; /* 10Gbps */
265 port
->duplex
= DUPLEX_FULL
;