Skip to content

Commit e4defc7

Browse files
David L Stevensdavem330
authored andcommitted
sunvnet: upgrade to VIO protocol version 1.6
This patch upgrades the sunvnet driver to support VIO protocol version 1.6. In particular, it adds per-port MTU negotiation, allowing MTUs other than ETH_FRAMELEN with ports using newer VIO protocol versions. Signed-off-by: David L Stevens <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent a12a601 commit e4defc7

File tree

4 files changed

+143
-22
lines changed

4 files changed

+143
-22
lines changed

arch/sparc/include/asm/vio.h

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ struct vio_dring_register {
6565
u16 options;
6666
#define VIO_TX_DRING 0x0001
6767
#define VIO_RX_DRING 0x0002
68+
#define VIO_RX_DRING_DATA 0x0004
6869
u16 resv;
6970
u32 num_cookies;
7071
struct ldc_trans_cookie cookies[0];
@@ -80,6 +81,8 @@ struct vio_dring_unregister {
8081
#define VIO_PKT_MODE 0x01 /* Packet based transfer */
8182
#define VIO_DESC_MODE 0x02 /* In-band descriptors */
8283
#define VIO_DRING_MODE 0x03 /* Descriptor rings */
84+
/* in vers >= 1.2, VIO_DRING_MODE is 0x04 and transfer mode is a bitmask */
85+
#define VIO_NEW_DRING_MODE 0x04
8386

8487
struct vio_dring_data {
8588
struct vio_msg_tag tag;
@@ -205,10 +208,20 @@ struct vio_net_attr_info {
205208
u8 addr_type;
206209
#define VNET_ADDR_ETHERMAC 0x01
207210
u16 ack_freq;
208-
u32 resv1;
211+
u8 plnk_updt;
212+
#define PHYSLINK_UPDATE_NONE 0x00
213+
#define PHYSLINK_UPDATE_STATE 0x01
214+
#define PHYSLINK_UPDATE_STATE_ACK 0x02
215+
#define PHYSLINK_UPDATE_STATE_NACK 0x03
216+
u8 options;
217+
u16 resv1;
209218
u64 addr;
210219
u64 mtu;
211-
u64 resv2[3];
220+
u16 cflags;
221+
#define VNET_LSO_IPV4_CAPAB 0x0001
222+
u16 ipv4_lso_maxlen;
223+
u32 resv2;
224+
u64 resv3[2];
212225
};
213226

214227
#define VNET_NUM_MCAST 7
@@ -366,6 +379,33 @@ struct vio_driver_state {
366379
struct vio_driver_ops *ops;
367380
};
368381

382+
static inline bool vio_version_before(struct vio_driver_state *vio,
383+
u16 major, u16 minor)
384+
{
385+
u32 have = (u32)vio->ver.major << 16 | vio->ver.minor;
386+
u32 want = (u32)major << 16 | minor;
387+
388+
return have < want;
389+
}
390+
391+
static inline bool vio_version_after(struct vio_driver_state *vio,
392+
u16 major, u16 minor)
393+
{
394+
u32 have = (u32)vio->ver.major << 16 | vio->ver.minor;
395+
u32 want = (u32)major << 16 | minor;
396+
397+
return have > want;
398+
}
399+
400+
static inline bool vio_version_after_eq(struct vio_driver_state *vio,
401+
u16 major, u16 minor)
402+
{
403+
u32 have = (u32)vio->ver.major << 16 | vio->ver.minor;
404+
u32 want = (u32)major << 16 | minor;
405+
406+
return have >= want;
407+
}
408+
369409
#define viodbg(TYPE, f, a...) \
370410
do { if (vio->debug & VIO_DEBUG_##TYPE) \
371411
printk(KERN_INFO "vio: ID[%lu] " f, \

arch/sparc/kernel/viohs.c

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,13 @@ static int process_dreg_info(struct vio_driver_state *vio,
426426
if (vio->dr_state & VIO_DR_STATE_RXREG)
427427
goto send_nack;
428428

429+
/* v1.6 and higher, ACK with desired, supported mode, or NACK */
430+
if (vio_version_after_eq(vio, 1, 6)) {
431+
if (!(pkt->options & VIO_TX_DRING))
432+
goto send_nack;
433+
pkt->options = VIO_TX_DRING;
434+
}
435+
429436
BUG_ON(vio->desc_buf);
430437

431438
vio->desc_buf = kzalloc(pkt->descr_size, GFP_ATOMIC);
@@ -453,8 +460,11 @@ static int process_dreg_info(struct vio_driver_state *vio,
453460
pkt->tag.stype = VIO_SUBTYPE_ACK;
454461
pkt->dring_ident = ++dr->ident;
455462

456-
viodbg(HS, "SEND DRING_REG ACK ident[%llx]\n",
457-
(unsigned long long) pkt->dring_ident);
463+
viodbg(HS, "SEND DRING_REG ACK ident[%llx] "
464+
"ndesc[%u] dsz[%u] opt[0x%x] ncookies[%u]\n",
465+
(unsigned long long) pkt->dring_ident,
466+
pkt->num_descr, pkt->descr_size, pkt->options,
467+
pkt->num_cookies);
458468

459469
len = (sizeof(*pkt) +
460470
(dr->ncookies * sizeof(struct ldc_trans_cookie)));

drivers/net/ethernet/sun/sunvnet.c

Lines changed: 86 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/ethtool.h>
1616
#include <linux/etherdevice.h>
1717
#include <linux/mutex.h>
18+
#include <linux/if_vlan.h>
1819

1920
#include <asm/vio.h>
2021
#include <asm/ldc.h>
@@ -41,6 +42,7 @@ static int __vnet_tx_trigger(struct vnet_port *port, u32 start);
4142

4243
/* Ordered from largest major to lowest */
4344
static struct vio_version vnet_versions[] = {
45+
{ .major = 1, .minor = 6 },
4446
{ .major = 1, .minor = 0 },
4547
};
4648

@@ -67,45 +69,102 @@ static int vnet_send_attr(struct vio_driver_state *vio)
6769
struct vnet_port *port = to_vnet_port(vio);
6870
struct net_device *dev = port->vp->dev;
6971
struct vio_net_attr_info pkt;
72+
int framelen = ETH_FRAME_LEN;
7073
int i;
7174

7275
memset(&pkt, 0, sizeof(pkt));
7376
pkt.tag.type = VIO_TYPE_CTRL;
7477
pkt.tag.stype = VIO_SUBTYPE_INFO;
7578
pkt.tag.stype_env = VIO_ATTR_INFO;
7679
pkt.tag.sid = vio_send_sid(vio);
77-
pkt.xfer_mode = VIO_DRING_MODE;
80+
if (vio_version_before(vio, 1, 2))
81+
pkt.xfer_mode = VIO_DRING_MODE;
82+
else
83+
pkt.xfer_mode = VIO_NEW_DRING_MODE;
7884
pkt.addr_type = VNET_ADDR_ETHERMAC;
7985
pkt.ack_freq = 0;
8086
for (i = 0; i < 6; i++)
8187
pkt.addr |= (u64)dev->dev_addr[i] << ((5 - i) * 8);
82-
pkt.mtu = ETH_FRAME_LEN;
88+
if (vio_version_after(vio, 1, 3)) {
89+
if (port->rmtu) {
90+
port->rmtu = min(VNET_MAXPACKET, port->rmtu);
91+
pkt.mtu = port->rmtu;
92+
} else {
93+
port->rmtu = VNET_MAXPACKET;
94+
pkt.mtu = port->rmtu;
95+
}
96+
if (vio_version_after_eq(vio, 1, 6))
97+
pkt.options = VIO_TX_DRING;
98+
} else if (vio_version_before(vio, 1, 3)) {
99+
pkt.mtu = framelen;
100+
} else { /* v1.3 */
101+
pkt.mtu = framelen + VLAN_HLEN;
102+
}
103+
104+
pkt.plnk_updt = PHYSLINK_UPDATE_NONE;
105+
pkt.cflags = 0;
83106

84107
viodbg(HS, "SEND NET ATTR xmode[0x%x] atype[0x%x] addr[%llx] "
85-
"ackfreq[%u] mtu[%llu]\n",
108+
"ackfreq[%u] plnk_updt[0x%02x] opts[0x%02x] mtu[%llu] "
109+
"cflags[0x%04x] lso_max[%u]\n",
86110
pkt.xfer_mode, pkt.addr_type,
87-
(unsigned long long) pkt.addr,
88-
pkt.ack_freq,
89-
(unsigned long long) pkt.mtu);
111+
(unsigned long long)pkt.addr,
112+
pkt.ack_freq, pkt.plnk_updt, pkt.options,
113+
(unsigned long long)pkt.mtu, pkt.cflags, pkt.ipv4_lso_maxlen);
114+
90115

91116
return vio_ldc_send(vio, &pkt, sizeof(pkt));
92117
}
93118

94119
static int handle_attr_info(struct vio_driver_state *vio,
95120
struct vio_net_attr_info *pkt)
96121
{
97-
viodbg(HS, "GOT NET ATTR INFO xmode[0x%x] atype[0x%x] addr[%llx] "
98-
"ackfreq[%u] mtu[%llu]\n",
122+
struct vnet_port *port = to_vnet_port(vio);
123+
u64 localmtu;
124+
u8 xfer_mode;
125+
126+
viodbg(HS, "GOT NET ATTR xmode[0x%x] atype[0x%x] addr[%llx] "
127+
"ackfreq[%u] plnk_updt[0x%02x] opts[0x%02x] mtu[%llu] "
128+
" (rmtu[%llu]) cflags[0x%04x] lso_max[%u]\n",
99129
pkt->xfer_mode, pkt->addr_type,
100-
(unsigned long long) pkt->addr,
101-
pkt->ack_freq,
102-
(unsigned long long) pkt->mtu);
130+
(unsigned long long)pkt->addr,
131+
pkt->ack_freq, pkt->plnk_updt, pkt->options,
132+
(unsigned long long)pkt->mtu, port->rmtu, pkt->cflags,
133+
pkt->ipv4_lso_maxlen);
103134

104135
pkt->tag.sid = vio_send_sid(vio);
105136

106-
if (pkt->xfer_mode != VIO_DRING_MODE ||
137+
xfer_mode = pkt->xfer_mode;
138+
/* for version < 1.2, VIO_DRING_MODE = 0x3 and no bitmask */
139+
if (vio_version_before(vio, 1, 2) && xfer_mode == VIO_DRING_MODE)
140+
xfer_mode = VIO_NEW_DRING_MODE;
141+
142+
/* MTU negotiation:
143+
* < v1.3 - ETH_FRAME_LEN exactly
144+
* > v1.3 - MIN(pkt.mtu, VNET_MAXPACKET, port->rmtu) and change
145+
* pkt->mtu for ACK
146+
* = v1.3 - ETH_FRAME_LEN + VLAN_HLEN exactly
147+
*/
148+
if (vio_version_before(vio, 1, 3)) {
149+
localmtu = ETH_FRAME_LEN;
150+
} else if (vio_version_after(vio, 1, 3)) {
151+
localmtu = port->rmtu ? port->rmtu : VNET_MAXPACKET;
152+
localmtu = min(pkt->mtu, localmtu);
153+
pkt->mtu = localmtu;
154+
} else { /* v1.3 */
155+
localmtu = ETH_FRAME_LEN + VLAN_HLEN;
156+
}
157+
port->rmtu = localmtu;
158+
159+
/* for version >= 1.6, ACK packet mode we support */
160+
if (vio_version_after_eq(vio, 1, 6)) {
161+
pkt->xfer_mode = VIO_NEW_DRING_MODE;
162+
pkt->options = VIO_TX_DRING;
163+
}
164+
165+
if (!(xfer_mode | VIO_NEW_DRING_MODE) ||
107166
pkt->addr_type != VNET_ADDR_ETHERMAC ||
108-
pkt->mtu != ETH_FRAME_LEN) {
167+
pkt->mtu != localmtu) {
109168
viodbg(HS, "SEND NET ATTR NACK\n");
110169

111170
pkt->tag.stype = VIO_SUBTYPE_NACK;
@@ -114,7 +173,14 @@ static int handle_attr_info(struct vio_driver_state *vio,
114173

115174
return -ECONNRESET;
116175
} else {
117-
viodbg(HS, "SEND NET ATTR ACK\n");
176+
viodbg(HS, "SEND NET ATTR ACK xmode[0x%x] atype[0x%x] "
177+
"addr[%llx] ackfreq[%u] plnk_updt[0x%02x] opts[0x%02x] "
178+
"mtu[%llu] (rmtu[%llu]) cflags[0x%04x] lso_max[%u]\n",
179+
pkt->xfer_mode, pkt->addr_type,
180+
(unsigned long long)pkt->addr,
181+
pkt->ack_freq, pkt->plnk_updt, pkt->options,
182+
(unsigned long long)pkt->mtu, port->rmtu, pkt->cflags,
183+
pkt->ipv4_lso_maxlen);
118184

119185
pkt->tag.stype = VIO_SUBTYPE_ACK;
120186

@@ -210,7 +276,7 @@ static int vnet_rx_one(struct vnet_port *port, unsigned int len,
210276
int err;
211277

212278
err = -EMSGSIZE;
213-
if (unlikely(len < ETH_ZLEN || len > ETH_FRAME_LEN)) {
279+
if (unlikely(len < ETH_ZLEN || len > port->rmtu)) {
214280
dev->stats.rx_length_errors++;
215281
goto out_dropped;
216282
}
@@ -558,8 +624,10 @@ static void vnet_event(void *arg, int event)
558624
vio_link_state_change(vio, event);
559625
spin_unlock_irqrestore(&vio->lock, flags);
560626

561-
if (event == LDC_EVENT_RESET)
627+
if (event == LDC_EVENT_RESET) {
628+
port->rmtu = 0;
562629
vio_port_up(vio);
630+
}
563631
return;
564632
}
565633

@@ -1051,8 +1119,8 @@ static int vnet_port_alloc_tx_bufs(struct vnet_port *port)
10511119
void *dring;
10521120

10531121
for (i = 0; i < VNET_TX_RING_SIZE; i++) {
1054-
void *buf = kzalloc(ETH_FRAME_LEN + 8, GFP_KERNEL);
1055-
int map_len = (ETH_FRAME_LEN + 7) & ~7;
1122+
void *buf = kzalloc(VNET_MAXPACKET + 8, GFP_KERNEL);
1123+
int map_len = (VNET_MAXPACKET + 7) & ~7;
10561124

10571125
err = -ENOMEM;
10581126
if (!buf)

drivers/net/ethernet/sun/sunvnet.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
*/
1212
#define VNET_TX_TIMEOUT (5 * HZ)
1313

14+
#define VNET_MAXPACKET 1518ULL /* ETH_FRAMELEN + VLAN_HDR */
1415
#define VNET_TX_RING_SIZE 512
1516
#define VNET_TX_WAKEUP_THRESH(dr) ((dr)->pending / 4)
1617

@@ -44,6 +45,8 @@ struct vnet_port {
4445
u32 stop_rx_idx;
4546
bool stop_rx;
4647
bool start_cons;
48+
49+
u64 rmtu;
4750
};
4851

4952
static inline struct vnet_port *to_vnet_port(struct vio_driver_state *vio)

0 commit comments

Comments
 (0)