diff options
-rw-r--r-- | arch/sparc/include/asm/vio.h | 44 | ||||
-rw-r--r-- | arch/sparc/kernel/ldc.c | 2 | ||||
-rw-r--r-- | arch/sparc/kernel/viohs.c | 14 | ||||
-rw-r--r-- | drivers/net/ethernet/sun/sunvnet.c | 358 | ||||
-rw-r--r-- | drivers/net/ethernet/sun/sunvnet.h | 16 |
5 files changed, 366 insertions, 68 deletions
diff --git a/arch/sparc/include/asm/vio.h b/arch/sparc/include/asm/vio.h index e0f6c399f1d0..6b135a8ab07b 100644 --- a/arch/sparc/include/asm/vio.h +++ b/arch/sparc/include/asm/vio.h | |||
@@ -65,6 +65,7 @@ struct vio_dring_register { | |||
65 | u16 options; | 65 | u16 options; |
66 | #define VIO_TX_DRING 0x0001 | 66 | #define VIO_TX_DRING 0x0001 |
67 | #define VIO_RX_DRING 0x0002 | 67 | #define VIO_RX_DRING 0x0002 |
68 | #define VIO_RX_DRING_DATA 0x0004 | ||
68 | u16 resv; | 69 | u16 resv; |
69 | u32 num_cookies; | 70 | u32 num_cookies; |
70 | struct ldc_trans_cookie cookies[0]; | 71 | struct ldc_trans_cookie cookies[0]; |
@@ -80,6 +81,8 @@ struct vio_dring_unregister { | |||
80 | #define VIO_PKT_MODE 0x01 /* Packet based transfer */ | 81 | #define VIO_PKT_MODE 0x01 /* Packet based transfer */ |
81 | #define VIO_DESC_MODE 0x02 /* In-band descriptors */ | 82 | #define VIO_DESC_MODE 0x02 /* In-band descriptors */ |
82 | #define VIO_DRING_MODE 0x03 /* Descriptor rings */ | 83 | #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 | ||
83 | 86 | ||
84 | struct vio_dring_data { | 87 | struct vio_dring_data { |
85 | struct vio_msg_tag tag; | 88 | struct vio_msg_tag tag; |
@@ -205,10 +208,20 @@ struct vio_net_attr_info { | |||
205 | u8 addr_type; | 208 | u8 addr_type; |
206 | #define VNET_ADDR_ETHERMAC 0x01 | 209 | #define VNET_ADDR_ETHERMAC 0x01 |
207 | u16 ack_freq; | 210 | 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; | ||
209 | u64 addr; | 218 | u64 addr; |
210 | u64 mtu; | 219 | 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]; | ||
212 | }; | 225 | }; |
213 | 226 | ||
214 | #define VNET_NUM_MCAST 7 | 227 | #define VNET_NUM_MCAST 7 |
@@ -366,6 +379,33 @@ struct vio_driver_state { | |||
366 | struct vio_driver_ops *ops; | 379 | struct vio_driver_ops *ops; |
367 | }; | 380 | }; |
368 | 381 | ||
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 | |||
369 | #define viodbg(TYPE, f, a...) \ | 409 | #define viodbg(TYPE, f, a...) \ |
370 | do { if (vio->debug & VIO_DEBUG_##TYPE) \ | 410 | do { if (vio->debug & VIO_DEBUG_##TYPE) \ |
371 | printk(KERN_INFO "vio: ID[%lu] " f, \ | 411 | printk(KERN_INFO "vio: ID[%lu] " f, \ |
diff --git a/arch/sparc/kernel/ldc.c b/arch/sparc/kernel/ldc.c index 66dacd56bb10..0af28b984695 100644 --- a/arch/sparc/kernel/ldc.c +++ b/arch/sparc/kernel/ldc.c | |||
@@ -2159,7 +2159,7 @@ int ldc_map_single(struct ldc_channel *lp, | |||
2159 | state.pte_idx = (base - iommu->page_table); | 2159 | state.pte_idx = (base - iommu->page_table); |
2160 | state.nc = 0; | 2160 | state.nc = 0; |
2161 | fill_cookies(&state, (pa & PAGE_MASK), (pa & ~PAGE_MASK), len); | 2161 | fill_cookies(&state, (pa & PAGE_MASK), (pa & ~PAGE_MASK), len); |
2162 | BUG_ON(state.nc != 1); | 2162 | BUG_ON(state.nc > ncookies); |
2163 | 2163 | ||
2164 | return state.nc; | 2164 | return state.nc; |
2165 | } | 2165 | } |
diff --git a/arch/sparc/kernel/viohs.c b/arch/sparc/kernel/viohs.c index f8e7dd53e1c7..7ef081a185b1 100644 --- a/arch/sparc/kernel/viohs.c +++ b/arch/sparc/kernel/viohs.c | |||
@@ -426,6 +426,13 @@ static int process_dreg_info(struct vio_driver_state *vio, | |||
426 | if (vio->dr_state & VIO_DR_STATE_RXREG) | 426 | if (vio->dr_state & VIO_DR_STATE_RXREG) |
427 | goto send_nack; | 427 | goto send_nack; |
428 | 428 | ||
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 | |||
429 | BUG_ON(vio->desc_buf); | 436 | BUG_ON(vio->desc_buf); |
430 | 437 | ||
431 | vio->desc_buf = kzalloc(pkt->descr_size, GFP_ATOMIC); | 438 | vio->desc_buf = kzalloc(pkt->descr_size, GFP_ATOMIC); |
@@ -453,8 +460,11 @@ static int process_dreg_info(struct vio_driver_state *vio, | |||
453 | pkt->tag.stype = VIO_SUBTYPE_ACK; | 460 | pkt->tag.stype = VIO_SUBTYPE_ACK; |
454 | pkt->dring_ident = ++dr->ident; | 461 | pkt->dring_ident = ++dr->ident; |
455 | 462 | ||
456 | viodbg(HS, "SEND DRING_REG ACK ident[%llx]\n", | 463 | viodbg(HS, "SEND DRING_REG ACK ident[%llx] " |
457 | (unsigned long long) pkt->dring_ident); | 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); | ||
458 | 468 | ||
459 | len = (sizeof(*pkt) + | 469 | len = (sizeof(*pkt) + |
460 | (dr->ncookies * sizeof(struct ldc_trans_cookie))); | 470 | (dr->ncookies * sizeof(struct ldc_trans_cookie))); |
diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c index edb860947da4..126269762ee7 100644 --- a/drivers/net/ethernet/sun/sunvnet.c +++ b/drivers/net/ethernet/sun/sunvnet.c | |||
@@ -15,6 +15,14 @@ | |||
15 | #include <linux/ethtool.h> | 15 | #include <linux/ethtool.h> |
16 | #include <linux/etherdevice.h> | 16 | #include <linux/etherdevice.h> |
17 | #include <linux/mutex.h> | 17 | #include <linux/mutex.h> |
18 | #include <linux/if_vlan.h> | ||
19 | |||
20 | #if IS_ENABLED(CONFIG_IPV6) | ||
21 | #include <linux/icmpv6.h> | ||
22 | #endif | ||
23 | |||
24 | #include <net/icmp.h> | ||
25 | #include <net/route.h> | ||
18 | 26 | ||
19 | #include <asm/vio.h> | 27 | #include <asm/vio.h> |
20 | #include <asm/ldc.h> | 28 | #include <asm/ldc.h> |
@@ -41,6 +49,7 @@ static int __vnet_tx_trigger(struct vnet_port *port, u32 start); | |||
41 | 49 | ||
42 | /* Ordered from largest major to lowest */ | 50 | /* Ordered from largest major to lowest */ |
43 | static struct vio_version vnet_versions[] = { | 51 | static struct vio_version vnet_versions[] = { |
52 | { .major = 1, .minor = 6 }, | ||
44 | { .major = 1, .minor = 0 }, | 53 | { .major = 1, .minor = 0 }, |
45 | }; | 54 | }; |
46 | 55 | ||
@@ -67,6 +76,7 @@ static int vnet_send_attr(struct vio_driver_state *vio) | |||
67 | struct vnet_port *port = to_vnet_port(vio); | 76 | struct vnet_port *port = to_vnet_port(vio); |
68 | struct net_device *dev = port->vp->dev; | 77 | struct net_device *dev = port->vp->dev; |
69 | struct vio_net_attr_info pkt; | 78 | struct vio_net_attr_info pkt; |
79 | int framelen = ETH_FRAME_LEN; | ||
70 | int i; | 80 | int i; |
71 | 81 | ||
72 | memset(&pkt, 0, sizeof(pkt)); | 82 | memset(&pkt, 0, sizeof(pkt)); |
@@ -74,19 +84,41 @@ static int vnet_send_attr(struct vio_driver_state *vio) | |||
74 | pkt.tag.stype = VIO_SUBTYPE_INFO; | 84 | pkt.tag.stype = VIO_SUBTYPE_INFO; |
75 | pkt.tag.stype_env = VIO_ATTR_INFO; | 85 | pkt.tag.stype_env = VIO_ATTR_INFO; |
76 | pkt.tag.sid = vio_send_sid(vio); | 86 | pkt.tag.sid = vio_send_sid(vio); |
77 | pkt.xfer_mode = VIO_DRING_MODE; | 87 | if (vio_version_before(vio, 1, 2)) |
88 | pkt.xfer_mode = VIO_DRING_MODE; | ||
89 | else | ||
90 | pkt.xfer_mode = VIO_NEW_DRING_MODE; | ||
78 | pkt.addr_type = VNET_ADDR_ETHERMAC; | 91 | pkt.addr_type = VNET_ADDR_ETHERMAC; |
79 | pkt.ack_freq = 0; | 92 | pkt.ack_freq = 0; |
80 | for (i = 0; i < 6; i++) | 93 | for (i = 0; i < 6; i++) |
81 | pkt.addr |= (u64)dev->dev_addr[i] << ((5 - i) * 8); | 94 | pkt.addr |= (u64)dev->dev_addr[i] << ((5 - i) * 8); |
82 | pkt.mtu = ETH_FRAME_LEN; | 95 | if (vio_version_after(vio, 1, 3)) { |
96 | if (port->rmtu) { | ||
97 | port->rmtu = min(VNET_MAXPACKET, port->rmtu); | ||
98 | pkt.mtu = port->rmtu; | ||
99 | } else { | ||
100 | port->rmtu = VNET_MAXPACKET; | ||
101 | pkt.mtu = port->rmtu; | ||
102 | } | ||
103 | if (vio_version_after_eq(vio, 1, 6)) | ||
104 | pkt.options = VIO_TX_DRING; | ||
105 | } else if (vio_version_before(vio, 1, 3)) { | ||
106 | pkt.mtu = framelen; | ||
107 | } else { /* v1.3 */ | ||
108 | pkt.mtu = framelen + VLAN_HLEN; | ||
109 | } | ||
110 | |||
111 | pkt.plnk_updt = PHYSLINK_UPDATE_NONE; | ||
112 | pkt.cflags = 0; | ||
83 | 113 | ||
84 | viodbg(HS, "SEND NET ATTR xmode[0x%x] atype[0x%x] addr[%llx] " | 114 | viodbg(HS, "SEND NET ATTR xmode[0x%x] atype[0x%x] addr[%llx] " |
85 | "ackfreq[%u] mtu[%llu]\n", | 115 | "ackfreq[%u] plnk_updt[0x%02x] opts[0x%02x] mtu[%llu] " |
116 | "cflags[0x%04x] lso_max[%u]\n", | ||
86 | pkt.xfer_mode, pkt.addr_type, | 117 | pkt.xfer_mode, pkt.addr_type, |
87 | (unsigned long long) pkt.addr, | 118 | (unsigned long long)pkt.addr, |
88 | pkt.ack_freq, | 119 | pkt.ack_freq, pkt.plnk_updt, pkt.options, |
89 | (unsigned long long) pkt.mtu); | 120 | (unsigned long long)pkt.mtu, pkt.cflags, pkt.ipv4_lso_maxlen); |
121 | |||
90 | 122 | ||
91 | return vio_ldc_send(vio, &pkt, sizeof(pkt)); | 123 | return vio_ldc_send(vio, &pkt, sizeof(pkt)); |
92 | } | 124 | } |
@@ -94,18 +126,52 @@ static int vnet_send_attr(struct vio_driver_state *vio) | |||
94 | static int handle_attr_info(struct vio_driver_state *vio, | 126 | static int handle_attr_info(struct vio_driver_state *vio, |
95 | struct vio_net_attr_info *pkt) | 127 | struct vio_net_attr_info *pkt) |
96 | { | 128 | { |
97 | viodbg(HS, "GOT NET ATTR INFO xmode[0x%x] atype[0x%x] addr[%llx] " | 129 | struct vnet_port *port = to_vnet_port(vio); |
98 | "ackfreq[%u] mtu[%llu]\n", | 130 | u64 localmtu; |
131 | u8 xfer_mode; | ||
132 | |||
133 | viodbg(HS, "GOT NET ATTR xmode[0x%x] atype[0x%x] addr[%llx] " | ||
134 | "ackfreq[%u] plnk_updt[0x%02x] opts[0x%02x] mtu[%llu] " | ||
135 | " (rmtu[%llu]) cflags[0x%04x] lso_max[%u]\n", | ||
99 | pkt->xfer_mode, pkt->addr_type, | 136 | pkt->xfer_mode, pkt->addr_type, |
100 | (unsigned long long) pkt->addr, | 137 | (unsigned long long)pkt->addr, |
101 | pkt->ack_freq, | 138 | pkt->ack_freq, pkt->plnk_updt, pkt->options, |
102 | (unsigned long long) pkt->mtu); | 139 | (unsigned long long)pkt->mtu, port->rmtu, pkt->cflags, |
140 | pkt->ipv4_lso_maxlen); | ||
103 | 141 | ||
104 | pkt->tag.sid = vio_send_sid(vio); | 142 | pkt->tag.sid = vio_send_sid(vio); |
105 | 143 | ||
106 | if (pkt->xfer_mode != VIO_DRING_MODE || | 144 | xfer_mode = pkt->xfer_mode; |
145 | /* for version < 1.2, VIO_DRING_MODE = 0x3 and no bitmask */ | ||
146 | if (vio_version_before(vio, 1, 2) && xfer_mode == VIO_DRING_MODE) | ||
147 | xfer_mode = VIO_NEW_DRING_MODE; | ||
148 | |||
149 | /* MTU negotiation: | ||
150 | * < v1.3 - ETH_FRAME_LEN exactly | ||
151 | * > v1.3 - MIN(pkt.mtu, VNET_MAXPACKET, port->rmtu) and change | ||
152 | * pkt->mtu for ACK | ||
153 | * = v1.3 - ETH_FRAME_LEN + VLAN_HLEN exactly | ||
154 | */ | ||
155 | if (vio_version_before(vio, 1, 3)) { | ||
156 | localmtu = ETH_FRAME_LEN; | ||
157 | } else if (vio_version_after(vio, 1, 3)) { | ||
158 | localmtu = port->rmtu ? port->rmtu : VNET_MAXPACKET; | ||
159 | localmtu = min(pkt->mtu, localmtu); | ||
160 | pkt->mtu = localmtu; | ||
161 | } else { /* v1.3 */ | ||
162 | localmtu = ETH_FRAME_LEN + VLAN_HLEN; | ||
163 | } | ||
164 | port->rmtu = localmtu; | ||
165 | |||
166 | /* for version >= 1.6, ACK packet mode we support */ | ||
167 | if (vio_version_after_eq(vio, 1, 6)) { | ||
168 | pkt->xfer_mode = VIO_NEW_DRING_MODE; | ||
169 | pkt->options = VIO_TX_DRING; | ||
170 | } | ||
171 | |||
172 | if (!(xfer_mode | VIO_NEW_DRING_MODE) || | ||
107 | pkt->addr_type != VNET_ADDR_ETHERMAC || | 173 | pkt->addr_type != VNET_ADDR_ETHERMAC || |
108 | pkt->mtu != ETH_FRAME_LEN) { | 174 | pkt->mtu != localmtu) { |
109 | viodbg(HS, "SEND NET ATTR NACK\n"); | 175 | viodbg(HS, "SEND NET ATTR NACK\n"); |
110 | 176 | ||
111 | pkt->tag.stype = VIO_SUBTYPE_NACK; | 177 | pkt->tag.stype = VIO_SUBTYPE_NACK; |
@@ -114,7 +180,14 @@ static int handle_attr_info(struct vio_driver_state *vio, | |||
114 | 180 | ||
115 | return -ECONNRESET; | 181 | return -ECONNRESET; |
116 | } else { | 182 | } else { |
117 | viodbg(HS, "SEND NET ATTR ACK\n"); | 183 | viodbg(HS, "SEND NET ATTR ACK xmode[0x%x] atype[0x%x] " |
184 | "addr[%llx] ackfreq[%u] plnk_updt[0x%02x] opts[0x%02x] " | ||
185 | "mtu[%llu] (rmtu[%llu]) cflags[0x%04x] lso_max[%u]\n", | ||
186 | pkt->xfer_mode, pkt->addr_type, | ||
187 | (unsigned long long)pkt->addr, | ||
188 | pkt->ack_freq, pkt->plnk_updt, pkt->options, | ||
189 | (unsigned long long)pkt->mtu, port->rmtu, pkt->cflags, | ||
190 | pkt->ipv4_lso_maxlen); | ||
118 | 191 | ||
119 | pkt->tag.stype = VIO_SUBTYPE_ACK; | 192 | pkt->tag.stype = VIO_SUBTYPE_ACK; |
120 | 193 | ||
@@ -210,7 +283,7 @@ static int vnet_rx_one(struct vnet_port *port, unsigned int len, | |||
210 | int err; | 283 | int err; |
211 | 284 | ||
212 | err = -EMSGSIZE; | 285 | err = -EMSGSIZE; |
213 | if (unlikely(len < ETH_ZLEN || len > ETH_FRAME_LEN)) { | 286 | if (unlikely(len < ETH_ZLEN || len > port->rmtu)) { |
214 | dev->stats.rx_length_errors++; | 287 | dev->stats.rx_length_errors++; |
215 | goto out_dropped; | 288 | goto out_dropped; |
216 | } | 289 | } |
@@ -558,8 +631,10 @@ static void vnet_event(void *arg, int event) | |||
558 | vio_link_state_change(vio, event); | 631 | vio_link_state_change(vio, event); |
559 | spin_unlock_irqrestore(&vio->lock, flags); | 632 | spin_unlock_irqrestore(&vio->lock, flags); |
560 | 633 | ||
561 | if (event == LDC_EVENT_RESET) | 634 | if (event == LDC_EVENT_RESET) { |
635 | port->rmtu = 0; | ||
562 | vio_port_up(vio); | 636 | vio_port_up(vio); |
637 | } | ||
563 | return; | 638 | return; |
564 | } | 639 | } |
565 | 640 | ||
@@ -712,6 +787,117 @@ struct vnet_port *tx_port_find(struct vnet *vp, struct sk_buff *skb) | |||
712 | return ret; | 787 | return ret; |
713 | } | 788 | } |
714 | 789 | ||
790 | static struct sk_buff *vnet_clean_tx_ring(struct vnet_port *port, | ||
791 | unsigned *pending) | ||
792 | { | ||
793 | struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING]; | ||
794 | struct sk_buff *skb = NULL; | ||
795 | int i, txi; | ||
796 | |||
797 | *pending = 0; | ||
798 | |||
799 | txi = dr->prod-1; | ||
800 | if (txi < 0) | ||
801 | txi = VNET_TX_RING_SIZE-1; | ||
802 | |||
803 | for (i = 0; i < VNET_TX_RING_SIZE; ++i) { | ||
804 | struct vio_net_desc *d; | ||
805 | |||
806 | d = vio_dring_entry(dr, txi); | ||
807 | |||
808 | if (d->hdr.state == VIO_DESC_DONE) { | ||
809 | if (port->tx_bufs[txi].skb) { | ||
810 | BUG_ON(port->tx_bufs[txi].skb->next); | ||
811 | |||
812 | port->tx_bufs[txi].skb->next = skb; | ||
813 | skb = port->tx_bufs[txi].skb; | ||
814 | port->tx_bufs[txi].skb = NULL; | ||
815 | |||
816 | ldc_unmap(port->vio.lp, | ||
817 | port->tx_bufs[txi].cookies, | ||
818 | port->tx_bufs[txi].ncookies); | ||
819 | } | ||
820 | d->hdr.state = VIO_DESC_FREE; | ||
821 | } else if (d->hdr.state == VIO_DESC_READY) { | ||
822 | (*pending)++; | ||
823 | } else if (d->hdr.state == VIO_DESC_FREE) { | ||
824 | break; | ||
825 | } | ||
826 | --txi; | ||
827 | if (txi < 0) | ||
828 | txi = VNET_TX_RING_SIZE-1; | ||
829 | } | ||
830 | return skb; | ||
831 | } | ||
832 | |||
833 | static inline void vnet_free_skbs(struct sk_buff *skb) | ||
834 | { | ||
835 | struct sk_buff *next; | ||
836 | |||
837 | while (skb) { | ||
838 | next = skb->next; | ||
839 | skb->next = NULL; | ||
840 | dev_kfree_skb(skb); | ||
841 | skb = next; | ||
842 | } | ||
843 | } | ||
844 | |||
845 | static void vnet_clean_timer_expire(unsigned long port0) | ||
846 | { | ||
847 | struct vnet_port *port = (struct vnet_port *)port0; | ||
848 | struct sk_buff *freeskbs; | ||
849 | unsigned pending; | ||
850 | unsigned long flags; | ||
851 | |||
852 | spin_lock_irqsave(&port->vio.lock, flags); | ||
853 | freeskbs = vnet_clean_tx_ring(port, &pending); | ||
854 | spin_unlock_irqrestore(&port->vio.lock, flags); | ||
855 | |||
856 | vnet_free_skbs(freeskbs); | ||
857 | |||
858 | if (pending) | ||
859 | (void)mod_timer(&port->clean_timer, | ||
860 | jiffies + VNET_CLEAN_TIMEOUT); | ||
861 | else | ||
862 | del_timer(&port->clean_timer); | ||
863 | } | ||
864 | |||
865 | static inline struct sk_buff *vnet_skb_shape(struct sk_buff *skb, void **pstart, | ||
866 | int *plen) | ||
867 | { | ||
868 | struct sk_buff *nskb; | ||
869 | int len, pad; | ||
870 | |||
871 | len = skb->len; | ||
872 | pad = 0; | ||
873 | if (len < ETH_ZLEN) { | ||
874 | pad += ETH_ZLEN - skb->len; | ||
875 | len += pad; | ||
876 | } | ||
877 | len += VNET_PACKET_SKIP; | ||
878 | pad += 8 - (len & 7); | ||
879 | len += 8 - (len & 7); | ||
880 | |||
881 | if (((unsigned long)skb->data & 7) != VNET_PACKET_SKIP || | ||
882 | skb_tailroom(skb) < pad || | ||
883 | skb_headroom(skb) < VNET_PACKET_SKIP) { | ||
884 | nskb = alloc_and_align_skb(skb->dev, skb->len); | ||
885 | skb_reserve(nskb, VNET_PACKET_SKIP); | ||
886 | if (skb_copy_bits(skb, 0, nskb->data, skb->len)) { | ||
887 | dev_kfree_skb(nskb); | ||
888 | dev_kfree_skb(skb); | ||
889 | return NULL; | ||
890 | } | ||
891 | (void)skb_put(nskb, skb->len); | ||
892 | dev_kfree_skb(skb); | ||
893 | skb = nskb; | ||
894 | } | ||
895 | |||
896 | *pstart = skb->data - VNET_PACKET_SKIP; | ||
897 | *plen = len; | ||
898 | return skb; | ||
899 | } | ||
900 | |||
715 | static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev) | 901 | static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev) |
716 | { | 902 | { |
717 | struct vnet *vp = netdev_priv(dev); | 903 | struct vnet *vp = netdev_priv(dev); |
@@ -720,12 +906,51 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
720 | struct vio_net_desc *d; | 906 | struct vio_net_desc *d; |
721 | unsigned long flags; | 907 | unsigned long flags; |
722 | unsigned int len; | 908 | unsigned int len; |
723 | void *tx_buf; | 909 | struct sk_buff *freeskbs = NULL; |
724 | int i, err; | 910 | int i, err, txi; |
911 | void *start = NULL; | ||
912 | int nlen = 0; | ||
913 | unsigned pending = 0; | ||
725 | 914 | ||
726 | if (unlikely(!port)) | 915 | if (unlikely(!port)) |
727 | goto out_dropped; | 916 | goto out_dropped; |
728 | 917 | ||
918 | skb = vnet_skb_shape(skb, &start, &nlen); | ||
919 | |||
920 | if (unlikely(!skb)) | ||
921 | goto out_dropped; | ||
922 | |||
923 | if (skb->len > port->rmtu) { | ||
924 | unsigned long localmtu = port->rmtu - ETH_HLEN; | ||
925 | |||
926 | if (vio_version_after_eq(&port->vio, 1, 3)) | ||
927 | localmtu -= VLAN_HLEN; | ||
928 | |||
929 | if (skb->protocol == htons(ETH_P_IP)) { | ||
930 | struct flowi4 fl4; | ||
931 | struct rtable *rt = NULL; | ||
932 | |||
933 | memset(&fl4, 0, sizeof(fl4)); | ||
934 | fl4.flowi4_oif = dev->ifindex; | ||
935 | fl4.flowi4_tos = RT_TOS(ip_hdr(skb)->tos); | ||
936 | fl4.daddr = ip_hdr(skb)->daddr; | ||
937 | fl4.saddr = ip_hdr(skb)->saddr; | ||
938 | |||
939 | rt = ip_route_output_key(dev_net(dev), &fl4); | ||
940 | if (!IS_ERR(rt)) { | ||
941 | skb_dst_set(skb, &rt->dst); | ||
942 | icmp_send(skb, ICMP_DEST_UNREACH, | ||
943 | ICMP_FRAG_NEEDED, | ||
944 | htonl(localmtu)); | ||
945 | } | ||
946 | } | ||
947 | #if IS_ENABLED(CONFIG_IPV6) | ||
948 | else if (skb->protocol == htons(ETH_P_IPV6)) | ||
949 | icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, localmtu); | ||
950 | #endif | ||
951 | goto out_dropped; | ||
952 | } | ||
953 | |||
729 | spin_lock_irqsave(&port->vio.lock, flags); | 954 | spin_lock_irqsave(&port->vio.lock, flags); |
730 | 955 | ||
731 | dr = &port->vio.drings[VIO_DRIVER_TX_RING]; | 956 | dr = &port->vio.drings[VIO_DRIVER_TX_RING]; |
@@ -743,14 +968,27 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
743 | 968 | ||
744 | d = vio_dring_cur(dr); | 969 | d = vio_dring_cur(dr); |
745 | 970 | ||
746 | tx_buf = port->tx_bufs[dr->prod].buf; | 971 | txi = dr->prod; |
747 | skb_copy_from_linear_data(skb, tx_buf + VNET_PACKET_SKIP, skb->len); | 972 | |
973 | freeskbs = vnet_clean_tx_ring(port, &pending); | ||
974 | |||
975 | BUG_ON(port->tx_bufs[txi].skb); | ||
748 | 976 | ||
749 | len = skb->len; | 977 | len = skb->len; |
750 | if (len < ETH_ZLEN) { | 978 | if (len < ETH_ZLEN) |
751 | len = ETH_ZLEN; | 979 | len = ETH_ZLEN; |
752 | memset(tx_buf+VNET_PACKET_SKIP+skb->len, 0, len - skb->len); | 980 | |
981 | port->tx_bufs[txi].skb = skb; | ||
982 | skb = NULL; | ||
983 | |||
984 | err = ldc_map_single(port->vio.lp, start, nlen, | ||
985 | port->tx_bufs[txi].cookies, VNET_MAXCOOKIES, | ||
986 | (LDC_MAP_SHADOW | LDC_MAP_DIRECT | LDC_MAP_RW)); | ||
987 | if (err < 0) { | ||
988 | netdev_info(dev, "tx buffer map error %d\n", err); | ||
989 | goto out_dropped_unlock; | ||
753 | } | 990 | } |
991 | port->tx_bufs[txi].ncookies = err; | ||
754 | 992 | ||
755 | /* We don't rely on the ACKs to free the skb in vnet_start_xmit(), | 993 | /* We don't rely on the ACKs to free the skb in vnet_start_xmit(), |
756 | * thus it is safe to not set VIO_ACK_ENABLE for each transmission: | 994 | * thus it is safe to not set VIO_ACK_ENABLE for each transmission: |
@@ -762,9 +1000,9 @@ static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev) | |||
762 | */ | 1000 | */ |
763 | d->hdr.ack = VIO_ACK_DISABLE; | 1001 | d->hdr.ack = VIO_ACK_DISABLE; |
764 | d->size = len; | 1002 | d->size = len; |
765 | d->ncookies = port->tx_bufs[dr->prod].ncookies; | 1003 | d->ncookies = port->tx_bufs[txi].ncookies; |
766 | for (i = 0; i < d->ncookies; i++) | 1004 | for (i = 0; i < d->ncookies; i++) |
767 | d->cookies[i] = port->tx_bufs[dr->prod].cookies[i]; | 1005 | d->cookies[i] = port->tx_bufs[txi].cookies[i]; |
768 | 1006 | ||
769 | /* This has to be a non-SMP write barrier because we are writing | 1007 | /* This has to be a non-SMP write barrier because we are writing |
770 | * to memory which is shared with the peer LDOM. | 1008 | * to memory which is shared with the peer LDOM. |
@@ -808,7 +1046,7 @@ ldc_start_done: | |||
808 | port->start_cons = false; | 1046 | port->start_cons = false; |
809 | 1047 | ||
810 | dev->stats.tx_packets++; | 1048 | dev->stats.tx_packets++; |
811 | dev->stats.tx_bytes += skb->len; | 1049 | dev->stats.tx_bytes += port->tx_bufs[txi].skb->len; |
812 | 1050 | ||
813 | dr->prod = (dr->prod + 1) & (VNET_TX_RING_SIZE - 1); | 1051 | dr->prod = (dr->prod + 1) & (VNET_TX_RING_SIZE - 1); |
814 | if (unlikely(vnet_tx_dring_avail(dr) < 2)) { | 1052 | if (unlikely(vnet_tx_dring_avail(dr) < 2)) { |
@@ -819,7 +1057,9 @@ ldc_start_done: | |||
819 | 1057 | ||
820 | spin_unlock_irqrestore(&port->vio.lock, flags); | 1058 | spin_unlock_irqrestore(&port->vio.lock, flags); |
821 | 1059 | ||
822 | dev_kfree_skb(skb); | 1060 | vnet_free_skbs(freeskbs); |
1061 | |||
1062 | (void)mod_timer(&port->clean_timer, jiffies + VNET_CLEAN_TIMEOUT); | ||
823 | 1063 | ||
824 | return NETDEV_TX_OK; | 1064 | return NETDEV_TX_OK; |
825 | 1065 | ||
@@ -827,7 +1067,14 @@ out_dropped_unlock: | |||
827 | spin_unlock_irqrestore(&port->vio.lock, flags); | 1067 | spin_unlock_irqrestore(&port->vio.lock, flags); |
828 | 1068 | ||
829 | out_dropped: | 1069 | out_dropped: |
830 | dev_kfree_skb(skb); | 1070 | if (skb) |
1071 | dev_kfree_skb(skb); | ||
1072 | vnet_free_skbs(freeskbs); | ||
1073 | if (pending) | ||
1074 | (void)mod_timer(&port->clean_timer, | ||
1075 | jiffies + VNET_CLEAN_TIMEOUT); | ||
1076 | else | ||
1077 | del_timer(&port->clean_timer); | ||
831 | dev->stats.tx_dropped++; | 1078 | dev->stats.tx_dropped++; |
832 | return NETDEV_TX_OK; | 1079 | return NETDEV_TX_OK; |
833 | } | 1080 | } |
@@ -973,7 +1220,7 @@ static void vnet_set_rx_mode(struct net_device *dev) | |||
973 | 1220 | ||
974 | static int vnet_change_mtu(struct net_device *dev, int new_mtu) | 1221 | static int vnet_change_mtu(struct net_device *dev, int new_mtu) |
975 | { | 1222 | { |
976 | if (new_mtu != ETH_DATA_LEN) | 1223 | if (new_mtu < 68 || new_mtu > 65535) |
977 | return -EINVAL; | 1224 | return -EINVAL; |
978 | 1225 | ||
979 | dev->mtu = new_mtu; | 1226 | dev->mtu = new_mtu; |
@@ -1029,17 +1276,22 @@ static void vnet_port_free_tx_bufs(struct vnet_port *port) | |||
1029 | } | 1276 | } |
1030 | 1277 | ||
1031 | for (i = 0; i < VNET_TX_RING_SIZE; i++) { | 1278 | for (i = 0; i < VNET_TX_RING_SIZE; i++) { |
1032 | void *buf = port->tx_bufs[i].buf; | 1279 | struct vio_net_desc *d; |
1280 | void *skb = port->tx_bufs[i].skb; | ||
1033 | 1281 | ||
1034 | if (!buf) | 1282 | if (!skb) |
1035 | continue; | 1283 | continue; |
1036 | 1284 | ||
1285 | d = vio_dring_entry(dr, i); | ||
1286 | if (d->hdr.state == VIO_DESC_READY) | ||
1287 | pr_warn("active transmit buffers freed\n"); | ||
1288 | |||
1037 | ldc_unmap(port->vio.lp, | 1289 | ldc_unmap(port->vio.lp, |
1038 | port->tx_bufs[i].cookies, | 1290 | port->tx_bufs[i].cookies, |
1039 | port->tx_bufs[i].ncookies); | 1291 | port->tx_bufs[i].ncookies); |
1040 | 1292 | dev_kfree_skb(skb); | |
1041 | kfree(buf); | 1293 | port->tx_bufs[i].skb = NULL; |
1042 | port->tx_bufs[i].buf = NULL; | 1294 | d->hdr.state = VIO_DESC_FREE; |
1043 | } | 1295 | } |
1044 | } | 1296 | } |
1045 | 1297 | ||
@@ -1050,34 +1302,6 @@ static int vnet_port_alloc_tx_bufs(struct vnet_port *port) | |||
1050 | int i, err, ncookies; | 1302 | int i, err, ncookies; |
1051 | void *dring; | 1303 | void *dring; |
1052 | 1304 | ||
1053 | 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; | ||
1056 | |||
1057 | err = -ENOMEM; | ||
1058 | if (!buf) | ||
1059 | goto err_out; | ||
1060 | |||
1061 | err = -EFAULT; | ||
1062 | if ((unsigned long)buf & (8UL - 1)) { | ||
1063 | pr_err("TX buffer misaligned\n"); | ||
1064 | kfree(buf); | ||
1065 | goto err_out; | ||
1066 | } | ||
1067 | |||
1068 | err = ldc_map_single(port->vio.lp, buf, map_len, | ||
1069 | port->tx_bufs[i].cookies, 2, | ||
1070 | (LDC_MAP_SHADOW | | ||
1071 | LDC_MAP_DIRECT | | ||
1072 | LDC_MAP_RW)); | ||
1073 | if (err < 0) { | ||
1074 | kfree(buf); | ||
1075 | goto err_out; | ||
1076 | } | ||
1077 | port->tx_bufs[i].buf = buf; | ||
1078 | port->tx_bufs[i].ncookies = err; | ||
1079 | } | ||
1080 | |||
1081 | dr = &port->vio.drings[VIO_DRIVER_TX_RING]; | 1305 | dr = &port->vio.drings[VIO_DRIVER_TX_RING]; |
1082 | 1306 | ||
1083 | len = (VNET_TX_RING_SIZE * | 1307 | len = (VNET_TX_RING_SIZE * |
@@ -1104,6 +1328,12 @@ static int vnet_port_alloc_tx_bufs(struct vnet_port *port) | |||
1104 | dr->pending = VNET_TX_RING_SIZE; | 1328 | dr->pending = VNET_TX_RING_SIZE; |
1105 | dr->ncookies = ncookies; | 1329 | dr->ncookies = ncookies; |
1106 | 1330 | ||
1331 | for (i = 0; i < VNET_TX_RING_SIZE; ++i) { | ||
1332 | struct vio_net_desc *d; | ||
1333 | |||
1334 | d = vio_dring_entry(dr, i); | ||
1335 | d->hdr.state = VIO_DESC_FREE; | ||
1336 | } | ||
1107 | return 0; | 1337 | return 0; |
1108 | 1338 | ||
1109 | err_out: | 1339 | err_out: |
@@ -1135,6 +1365,8 @@ static struct vnet *vnet_new(const u64 *local_mac) | |||
1135 | dev = alloc_etherdev(sizeof(*vp)); | 1365 | dev = alloc_etherdev(sizeof(*vp)); |
1136 | if (!dev) | 1366 | if (!dev) |
1137 | return ERR_PTR(-ENOMEM); | 1367 | return ERR_PTR(-ENOMEM); |
1368 | dev->needed_headroom = VNET_PACKET_SKIP + 8; | ||
1369 | dev->needed_tailroom = 8; | ||
1138 | 1370 | ||
1139 | for (i = 0; i < ETH_ALEN; i++) | 1371 | for (i = 0; i < ETH_ALEN; i++) |
1140 | dev->dev_addr[i] = (*local_mac >> (5 - i) * 8) & 0xff; | 1372 | dev->dev_addr[i] = (*local_mac >> (5 - i) * 8) & 0xff; |
@@ -1329,6 +1561,9 @@ static int vnet_port_probe(struct vio_dev *vdev, const struct vio_device_id *id) | |||
1329 | pr_info("%s: PORT ( remote-mac %pM%s )\n", | 1561 | pr_info("%s: PORT ( remote-mac %pM%s )\n", |
1330 | vp->dev->name, port->raddr, switch_port ? " switch-port" : ""); | 1562 | vp->dev->name, port->raddr, switch_port ? " switch-port" : ""); |
1331 | 1563 | ||
1564 | setup_timer(&port->clean_timer, vnet_clean_timer_expire, | ||
1565 | (unsigned long)port); | ||
1566 | |||
1332 | vio_port_up(&port->vio); | 1567 | vio_port_up(&port->vio); |
1333 | 1568 | ||
1334 | mdesc_release(hp); | 1569 | mdesc_release(hp); |
@@ -1355,6 +1590,7 @@ static int vnet_port_remove(struct vio_dev *vdev) | |||
1355 | unsigned long flags; | 1590 | unsigned long flags; |
1356 | 1591 | ||
1357 | del_timer_sync(&port->vio.timer); | 1592 | del_timer_sync(&port->vio.timer); |
1593 | del_timer_sync(&port->clean_timer); | ||
1358 | 1594 | ||
1359 | spin_lock_irqsave(&vp->lock, flags); | 1595 | spin_lock_irqsave(&vp->lock, flags); |
1360 | list_del(&port->list); | 1596 | list_del(&port->list); |
diff --git a/drivers/net/ethernet/sun/sunvnet.h b/drivers/net/ethernet/sun/sunvnet.h index da4933750d06..c91104542619 100644 --- a/drivers/net/ethernet/sun/sunvnet.h +++ b/drivers/net/ethernet/sun/sunvnet.h | |||
@@ -11,6 +11,12 @@ | |||
11 | */ | 11 | */ |
12 | #define VNET_TX_TIMEOUT (5 * HZ) | 12 | #define VNET_TX_TIMEOUT (5 * HZ) |
13 | 13 | ||
14 | /* length of time (or less) we expect pending descriptors to be marked | ||
15 | * as VIO_DESC_DONE and skbs ready to be freed | ||
16 | */ | ||
17 | #define VNET_CLEAN_TIMEOUT ((HZ/100)+1) | ||
18 | |||
19 | #define VNET_MAXPACKET (65535ULL + ETH_HLEN + VLAN_HLEN) | ||
14 | #define VNET_TX_RING_SIZE 512 | 20 | #define VNET_TX_RING_SIZE 512 |
15 | #define VNET_TX_WAKEUP_THRESH(dr) ((dr)->pending / 4) | 21 | #define VNET_TX_WAKEUP_THRESH(dr) ((dr)->pending / 4) |
16 | 22 | ||
@@ -20,10 +26,12 @@ | |||
20 | */ | 26 | */ |
21 | #define VNET_PACKET_SKIP 6 | 27 | #define VNET_PACKET_SKIP 6 |
22 | 28 | ||
29 | #define VNET_MAXCOOKIES (VNET_MAXPACKET/PAGE_SIZE + 1) | ||
30 | |||
23 | struct vnet_tx_entry { | 31 | struct vnet_tx_entry { |
24 | void *buf; | 32 | struct sk_buff *skb; |
25 | unsigned int ncookies; | 33 | unsigned int ncookies; |
26 | struct ldc_trans_cookie cookies[2]; | 34 | struct ldc_trans_cookie cookies[VNET_MAXCOOKIES]; |
27 | }; | 35 | }; |
28 | 36 | ||
29 | struct vnet; | 37 | struct vnet; |
@@ -44,6 +52,10 @@ struct vnet_port { | |||
44 | u32 stop_rx_idx; | 52 | u32 stop_rx_idx; |
45 | bool stop_rx; | 53 | bool stop_rx; |
46 | bool start_cons; | 54 | bool start_cons; |
55 | |||
56 | struct timer_list clean_timer; | ||
57 | |||
58 | u64 rmtu; | ||
47 | }; | 59 | }; |
48 | 60 | ||
49 | static inline struct vnet_port *to_vnet_port(struct vio_driver_state *vio) | 61 | static inline struct vnet_port *to_vnet_port(struct vio_driver_state *vio) |