1e689cf4aSJeff Kirsher /* sunvnet.c: Sun LDOM Virtual Network Driver. 2e689cf4aSJeff Kirsher * 3e689cf4aSJeff Kirsher * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net> 4e689cf4aSJeff Kirsher */ 5e689cf4aSJeff Kirsher 6e689cf4aSJeff Kirsher #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 7e689cf4aSJeff Kirsher 8e689cf4aSJeff Kirsher #include <linux/module.h> 9e689cf4aSJeff Kirsher #include <linux/kernel.h> 10e689cf4aSJeff Kirsher #include <linux/types.h> 11e689cf4aSJeff Kirsher #include <linux/slab.h> 12e689cf4aSJeff Kirsher #include <linux/delay.h> 13e689cf4aSJeff Kirsher #include <linux/init.h> 14e689cf4aSJeff Kirsher #include <linux/netdevice.h> 15e689cf4aSJeff Kirsher #include <linux/ethtool.h> 16e689cf4aSJeff Kirsher #include <linux/etherdevice.h> 17e689cf4aSJeff Kirsher #include <linux/mutex.h> 18e689cf4aSJeff Kirsher 19e689cf4aSJeff Kirsher #include <asm/vio.h> 20e689cf4aSJeff Kirsher #include <asm/ldc.h> 21e689cf4aSJeff Kirsher 22e689cf4aSJeff Kirsher #include "sunvnet.h" 23e689cf4aSJeff Kirsher 24e689cf4aSJeff Kirsher #define DRV_MODULE_NAME "sunvnet" 25e689cf4aSJeff Kirsher #define DRV_MODULE_VERSION "1.0" 26e689cf4aSJeff Kirsher #define DRV_MODULE_RELDATE "June 25, 2007" 27e689cf4aSJeff Kirsher 28f73d12bdSBill Pemberton static char version[] = 29e689cf4aSJeff Kirsher DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; 30e689cf4aSJeff Kirsher MODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); 31e689cf4aSJeff Kirsher MODULE_DESCRIPTION("Sun LDOM virtual network driver"); 32e689cf4aSJeff Kirsher MODULE_LICENSE("GPL"); 33e689cf4aSJeff Kirsher MODULE_VERSION(DRV_MODULE_VERSION); 34e689cf4aSJeff Kirsher 35e689cf4aSJeff Kirsher /* Ordered from largest major to lowest */ 36e689cf4aSJeff Kirsher static struct vio_version vnet_versions[] = { 37e689cf4aSJeff Kirsher { .major = 1, .minor = 0 }, 38e689cf4aSJeff Kirsher }; 39e689cf4aSJeff Kirsher 40e689cf4aSJeff Kirsher static inline u32 vnet_tx_dring_avail(struct vio_dring_state *dr) 41e689cf4aSJeff Kirsher { 42e689cf4aSJeff Kirsher return vio_dring_avail(dr, VNET_TX_RING_SIZE); 43e689cf4aSJeff Kirsher } 44e689cf4aSJeff Kirsher 45e689cf4aSJeff Kirsher static int vnet_handle_unknown(struct vnet_port *port, void *arg) 46e689cf4aSJeff Kirsher { 47e689cf4aSJeff Kirsher struct vio_msg_tag *pkt = arg; 48e689cf4aSJeff Kirsher 49e689cf4aSJeff Kirsher pr_err("Received unknown msg [%02x:%02x:%04x:%08x]\n", 50e689cf4aSJeff Kirsher pkt->type, pkt->stype, pkt->stype_env, pkt->sid); 51e689cf4aSJeff Kirsher pr_err("Resetting connection\n"); 52e689cf4aSJeff Kirsher 53e689cf4aSJeff Kirsher ldc_disconnect(port->vio.lp); 54e689cf4aSJeff Kirsher 55e689cf4aSJeff Kirsher return -ECONNRESET; 56e689cf4aSJeff Kirsher } 57e689cf4aSJeff Kirsher 58e689cf4aSJeff Kirsher static int vnet_send_attr(struct vio_driver_state *vio) 59e689cf4aSJeff Kirsher { 60e689cf4aSJeff Kirsher struct vnet_port *port = to_vnet_port(vio); 61e689cf4aSJeff Kirsher struct net_device *dev = port->vp->dev; 62e689cf4aSJeff Kirsher struct vio_net_attr_info pkt; 63e689cf4aSJeff Kirsher int i; 64e689cf4aSJeff Kirsher 65e689cf4aSJeff Kirsher memset(&pkt, 0, sizeof(pkt)); 66e689cf4aSJeff Kirsher pkt.tag.type = VIO_TYPE_CTRL; 67e689cf4aSJeff Kirsher pkt.tag.stype = VIO_SUBTYPE_INFO; 68e689cf4aSJeff Kirsher pkt.tag.stype_env = VIO_ATTR_INFO; 69e689cf4aSJeff Kirsher pkt.tag.sid = vio_send_sid(vio); 70e689cf4aSJeff Kirsher pkt.xfer_mode = VIO_DRING_MODE; 71e689cf4aSJeff Kirsher pkt.addr_type = VNET_ADDR_ETHERMAC; 72e689cf4aSJeff Kirsher pkt.ack_freq = 0; 73e689cf4aSJeff Kirsher for (i = 0; i < 6; i++) 74e689cf4aSJeff Kirsher pkt.addr |= (u64)dev->dev_addr[i] << ((5 - i) * 8); 75e689cf4aSJeff Kirsher pkt.mtu = ETH_FRAME_LEN; 76e689cf4aSJeff Kirsher 77e689cf4aSJeff Kirsher viodbg(HS, "SEND NET ATTR xmode[0x%x] atype[0x%x] addr[%llx] " 78e689cf4aSJeff Kirsher "ackfreq[%u] mtu[%llu]\n", 79e689cf4aSJeff Kirsher pkt.xfer_mode, pkt.addr_type, 80e689cf4aSJeff Kirsher (unsigned long long) pkt.addr, 81e689cf4aSJeff Kirsher pkt.ack_freq, 82e689cf4aSJeff Kirsher (unsigned long long) pkt.mtu); 83e689cf4aSJeff Kirsher 84e689cf4aSJeff Kirsher return vio_ldc_send(vio, &pkt, sizeof(pkt)); 85e689cf4aSJeff Kirsher } 86e689cf4aSJeff Kirsher 87e689cf4aSJeff Kirsher static int handle_attr_info(struct vio_driver_state *vio, 88e689cf4aSJeff Kirsher struct vio_net_attr_info *pkt) 89e689cf4aSJeff Kirsher { 90e689cf4aSJeff Kirsher viodbg(HS, "GOT NET ATTR INFO xmode[0x%x] atype[0x%x] addr[%llx] " 91e689cf4aSJeff Kirsher "ackfreq[%u] mtu[%llu]\n", 92e689cf4aSJeff Kirsher pkt->xfer_mode, pkt->addr_type, 93e689cf4aSJeff Kirsher (unsigned long long) pkt->addr, 94e689cf4aSJeff Kirsher pkt->ack_freq, 95e689cf4aSJeff Kirsher (unsigned long long) pkt->mtu); 96e689cf4aSJeff Kirsher 97e689cf4aSJeff Kirsher pkt->tag.sid = vio_send_sid(vio); 98e689cf4aSJeff Kirsher 99e689cf4aSJeff Kirsher if (pkt->xfer_mode != VIO_DRING_MODE || 100e689cf4aSJeff Kirsher pkt->addr_type != VNET_ADDR_ETHERMAC || 101e689cf4aSJeff Kirsher pkt->mtu != ETH_FRAME_LEN) { 102e689cf4aSJeff Kirsher viodbg(HS, "SEND NET ATTR NACK\n"); 103e689cf4aSJeff Kirsher 104e689cf4aSJeff Kirsher pkt->tag.stype = VIO_SUBTYPE_NACK; 105e689cf4aSJeff Kirsher 106e689cf4aSJeff Kirsher (void) vio_ldc_send(vio, pkt, sizeof(*pkt)); 107e689cf4aSJeff Kirsher 108e689cf4aSJeff Kirsher return -ECONNRESET; 109e689cf4aSJeff Kirsher } else { 110e689cf4aSJeff Kirsher viodbg(HS, "SEND NET ATTR ACK\n"); 111e689cf4aSJeff Kirsher 112e689cf4aSJeff Kirsher pkt->tag.stype = VIO_SUBTYPE_ACK; 113e689cf4aSJeff Kirsher 114e689cf4aSJeff Kirsher return vio_ldc_send(vio, pkt, sizeof(*pkt)); 115e689cf4aSJeff Kirsher } 116e689cf4aSJeff Kirsher 117e689cf4aSJeff Kirsher } 118e689cf4aSJeff Kirsher 119e689cf4aSJeff Kirsher static int handle_attr_ack(struct vio_driver_state *vio, 120e689cf4aSJeff Kirsher struct vio_net_attr_info *pkt) 121e689cf4aSJeff Kirsher { 122e689cf4aSJeff Kirsher viodbg(HS, "GOT NET ATTR ACK\n"); 123e689cf4aSJeff Kirsher 124e689cf4aSJeff Kirsher return 0; 125e689cf4aSJeff Kirsher } 126e689cf4aSJeff Kirsher 127e689cf4aSJeff Kirsher static int handle_attr_nack(struct vio_driver_state *vio, 128e689cf4aSJeff Kirsher struct vio_net_attr_info *pkt) 129e689cf4aSJeff Kirsher { 130e689cf4aSJeff Kirsher viodbg(HS, "GOT NET ATTR NACK\n"); 131e689cf4aSJeff Kirsher 132e689cf4aSJeff Kirsher return -ECONNRESET; 133e689cf4aSJeff Kirsher } 134e689cf4aSJeff Kirsher 135e689cf4aSJeff Kirsher static int vnet_handle_attr(struct vio_driver_state *vio, void *arg) 136e689cf4aSJeff Kirsher { 137e689cf4aSJeff Kirsher struct vio_net_attr_info *pkt = arg; 138e689cf4aSJeff Kirsher 139e689cf4aSJeff Kirsher switch (pkt->tag.stype) { 140e689cf4aSJeff Kirsher case VIO_SUBTYPE_INFO: 141e689cf4aSJeff Kirsher return handle_attr_info(vio, pkt); 142e689cf4aSJeff Kirsher 143e689cf4aSJeff Kirsher case VIO_SUBTYPE_ACK: 144e689cf4aSJeff Kirsher return handle_attr_ack(vio, pkt); 145e689cf4aSJeff Kirsher 146e689cf4aSJeff Kirsher case VIO_SUBTYPE_NACK: 147e689cf4aSJeff Kirsher return handle_attr_nack(vio, pkt); 148e689cf4aSJeff Kirsher 149e689cf4aSJeff Kirsher default: 150e689cf4aSJeff Kirsher return -ECONNRESET; 151e689cf4aSJeff Kirsher } 152e689cf4aSJeff Kirsher } 153e689cf4aSJeff Kirsher 154e689cf4aSJeff Kirsher static void vnet_handshake_complete(struct vio_driver_state *vio) 155e689cf4aSJeff Kirsher { 156e689cf4aSJeff Kirsher struct vio_dring_state *dr; 157e689cf4aSJeff Kirsher 158e689cf4aSJeff Kirsher dr = &vio->drings[VIO_DRIVER_RX_RING]; 159e689cf4aSJeff Kirsher dr->snd_nxt = dr->rcv_nxt = 1; 160e689cf4aSJeff Kirsher 161e689cf4aSJeff Kirsher dr = &vio->drings[VIO_DRIVER_TX_RING]; 162e689cf4aSJeff Kirsher dr->snd_nxt = dr->rcv_nxt = 1; 163e689cf4aSJeff Kirsher } 164e689cf4aSJeff Kirsher 165e689cf4aSJeff Kirsher /* The hypervisor interface that implements copying to/from imported 166e689cf4aSJeff Kirsher * memory from another domain requires that copies are done to 8-byte 167e689cf4aSJeff Kirsher * aligned buffers, and that the lengths of such copies are also 8-byte 168e689cf4aSJeff Kirsher * multiples. 169e689cf4aSJeff Kirsher * 170e689cf4aSJeff Kirsher * So we align skb->data to an 8-byte multiple and pad-out the data 171e689cf4aSJeff Kirsher * area so we can round the copy length up to the next multiple of 172e689cf4aSJeff Kirsher * 8 for the copy. 173e689cf4aSJeff Kirsher * 174e689cf4aSJeff Kirsher * The transmitter puts the actual start of the packet 6 bytes into 175e689cf4aSJeff Kirsher * the buffer it sends over, so that the IP headers after the ethernet 176e689cf4aSJeff Kirsher * header are aligned properly. These 6 bytes are not in the descriptor 177e689cf4aSJeff Kirsher * length, they are simply implied. This offset is represented using 178e689cf4aSJeff Kirsher * the VNET_PACKET_SKIP macro. 179e689cf4aSJeff Kirsher */ 180e689cf4aSJeff Kirsher static struct sk_buff *alloc_and_align_skb(struct net_device *dev, 181e689cf4aSJeff Kirsher unsigned int len) 182e689cf4aSJeff Kirsher { 183e689cf4aSJeff Kirsher struct sk_buff *skb = netdev_alloc_skb(dev, len+VNET_PACKET_SKIP+8+8); 184e689cf4aSJeff Kirsher unsigned long addr, off; 185e689cf4aSJeff Kirsher 186e689cf4aSJeff Kirsher if (unlikely(!skb)) 187e689cf4aSJeff Kirsher return NULL; 188e689cf4aSJeff Kirsher 189e689cf4aSJeff Kirsher addr = (unsigned long) skb->data; 190e689cf4aSJeff Kirsher off = ((addr + 7UL) & ~7UL) - addr; 191e689cf4aSJeff Kirsher if (off) 192e689cf4aSJeff Kirsher skb_reserve(skb, off); 193e689cf4aSJeff Kirsher 194e689cf4aSJeff Kirsher return skb; 195e689cf4aSJeff Kirsher } 196e689cf4aSJeff Kirsher 197e689cf4aSJeff Kirsher static int vnet_rx_one(struct vnet_port *port, unsigned int len, 198e689cf4aSJeff Kirsher struct ldc_trans_cookie *cookies, int ncookies) 199e689cf4aSJeff Kirsher { 200e689cf4aSJeff Kirsher struct net_device *dev = port->vp->dev; 201e689cf4aSJeff Kirsher unsigned int copy_len; 202e689cf4aSJeff Kirsher struct sk_buff *skb; 203e689cf4aSJeff Kirsher int err; 204e689cf4aSJeff Kirsher 205e689cf4aSJeff Kirsher err = -EMSGSIZE; 206e689cf4aSJeff Kirsher if (unlikely(len < ETH_ZLEN || len > ETH_FRAME_LEN)) { 207e689cf4aSJeff Kirsher dev->stats.rx_length_errors++; 208e689cf4aSJeff Kirsher goto out_dropped; 209e689cf4aSJeff Kirsher } 210e689cf4aSJeff Kirsher 211e689cf4aSJeff Kirsher skb = alloc_and_align_skb(dev, len); 212e689cf4aSJeff Kirsher err = -ENOMEM; 213e689cf4aSJeff Kirsher if (unlikely(!skb)) { 214e689cf4aSJeff Kirsher dev->stats.rx_missed_errors++; 215e689cf4aSJeff Kirsher goto out_dropped; 216e689cf4aSJeff Kirsher } 217e689cf4aSJeff Kirsher 218e689cf4aSJeff Kirsher copy_len = (len + VNET_PACKET_SKIP + 7U) & ~7U; 219e689cf4aSJeff Kirsher skb_put(skb, copy_len); 220e689cf4aSJeff Kirsher err = ldc_copy(port->vio.lp, LDC_COPY_IN, 221e689cf4aSJeff Kirsher skb->data, copy_len, 0, 222e689cf4aSJeff Kirsher cookies, ncookies); 223e689cf4aSJeff Kirsher if (unlikely(err < 0)) { 224e689cf4aSJeff Kirsher dev->stats.rx_frame_errors++; 225e689cf4aSJeff Kirsher goto out_free_skb; 226e689cf4aSJeff Kirsher } 227e689cf4aSJeff Kirsher 228e689cf4aSJeff Kirsher skb_pull(skb, VNET_PACKET_SKIP); 229e689cf4aSJeff Kirsher skb_trim(skb, len); 230e689cf4aSJeff Kirsher skb->protocol = eth_type_trans(skb, dev); 231e689cf4aSJeff Kirsher 232e689cf4aSJeff Kirsher dev->stats.rx_packets++; 233e689cf4aSJeff Kirsher dev->stats.rx_bytes += len; 234e689cf4aSJeff Kirsher 235e689cf4aSJeff Kirsher netif_rx(skb); 236e689cf4aSJeff Kirsher 237e689cf4aSJeff Kirsher return 0; 238e689cf4aSJeff Kirsher 239e689cf4aSJeff Kirsher out_free_skb: 240e689cf4aSJeff Kirsher kfree_skb(skb); 241e689cf4aSJeff Kirsher 242e689cf4aSJeff Kirsher out_dropped: 243e689cf4aSJeff Kirsher dev->stats.rx_dropped++; 244e689cf4aSJeff Kirsher return err; 245e689cf4aSJeff Kirsher } 246e689cf4aSJeff Kirsher 247e689cf4aSJeff Kirsher static int vnet_send_ack(struct vnet_port *port, struct vio_dring_state *dr, 248e689cf4aSJeff Kirsher u32 start, u32 end, u8 vio_dring_state) 249e689cf4aSJeff Kirsher { 250e689cf4aSJeff Kirsher struct vio_dring_data hdr = { 251e689cf4aSJeff Kirsher .tag = { 252e689cf4aSJeff Kirsher .type = VIO_TYPE_DATA, 253e689cf4aSJeff Kirsher .stype = VIO_SUBTYPE_ACK, 254e689cf4aSJeff Kirsher .stype_env = VIO_DRING_DATA, 255e689cf4aSJeff Kirsher .sid = vio_send_sid(&port->vio), 256e689cf4aSJeff Kirsher }, 257e689cf4aSJeff Kirsher .dring_ident = dr->ident, 258e689cf4aSJeff Kirsher .start_idx = start, 259e689cf4aSJeff Kirsher .end_idx = end, 260e689cf4aSJeff Kirsher .state = vio_dring_state, 261e689cf4aSJeff Kirsher }; 262e689cf4aSJeff Kirsher int err, delay; 263e689cf4aSJeff Kirsher 264e689cf4aSJeff Kirsher hdr.seq = dr->snd_nxt; 265e689cf4aSJeff Kirsher delay = 1; 266e689cf4aSJeff Kirsher do { 267e689cf4aSJeff Kirsher err = vio_ldc_send(&port->vio, &hdr, sizeof(hdr)); 268e689cf4aSJeff Kirsher if (err > 0) { 269e689cf4aSJeff Kirsher dr->snd_nxt++; 270e689cf4aSJeff Kirsher break; 271e689cf4aSJeff Kirsher } 272e689cf4aSJeff Kirsher udelay(delay); 273e689cf4aSJeff Kirsher if ((delay <<= 1) > 128) 274e689cf4aSJeff Kirsher delay = 128; 275e689cf4aSJeff Kirsher } while (err == -EAGAIN); 276e689cf4aSJeff Kirsher 277e689cf4aSJeff Kirsher return err; 278e689cf4aSJeff Kirsher } 279e689cf4aSJeff Kirsher 280e689cf4aSJeff Kirsher static u32 next_idx(u32 idx, struct vio_dring_state *dr) 281e689cf4aSJeff Kirsher { 282e689cf4aSJeff Kirsher if (++idx == dr->num_entries) 283e689cf4aSJeff Kirsher idx = 0; 284e689cf4aSJeff Kirsher return idx; 285e689cf4aSJeff Kirsher } 286e689cf4aSJeff Kirsher 287e689cf4aSJeff Kirsher static u32 prev_idx(u32 idx, struct vio_dring_state *dr) 288e689cf4aSJeff Kirsher { 289e689cf4aSJeff Kirsher if (idx == 0) 290e689cf4aSJeff Kirsher idx = dr->num_entries - 1; 291e689cf4aSJeff Kirsher else 292e689cf4aSJeff Kirsher idx--; 293e689cf4aSJeff Kirsher 294e689cf4aSJeff Kirsher return idx; 295e689cf4aSJeff Kirsher } 296e689cf4aSJeff Kirsher 297e689cf4aSJeff Kirsher static struct vio_net_desc *get_rx_desc(struct vnet_port *port, 298e689cf4aSJeff Kirsher struct vio_dring_state *dr, 299e689cf4aSJeff Kirsher u32 index) 300e689cf4aSJeff Kirsher { 301e689cf4aSJeff Kirsher struct vio_net_desc *desc = port->vio.desc_buf; 302e689cf4aSJeff Kirsher int err; 303e689cf4aSJeff Kirsher 304e689cf4aSJeff Kirsher err = ldc_get_dring_entry(port->vio.lp, desc, dr->entry_size, 305e689cf4aSJeff Kirsher (index * dr->entry_size), 306e689cf4aSJeff Kirsher dr->cookies, dr->ncookies); 307e689cf4aSJeff Kirsher if (err < 0) 308e689cf4aSJeff Kirsher return ERR_PTR(err); 309e689cf4aSJeff Kirsher 310e689cf4aSJeff Kirsher return desc; 311e689cf4aSJeff Kirsher } 312e689cf4aSJeff Kirsher 313e689cf4aSJeff Kirsher static int put_rx_desc(struct vnet_port *port, 314e689cf4aSJeff Kirsher struct vio_dring_state *dr, 315e689cf4aSJeff Kirsher struct vio_net_desc *desc, 316e689cf4aSJeff Kirsher u32 index) 317e689cf4aSJeff Kirsher { 318e689cf4aSJeff Kirsher int err; 319e689cf4aSJeff Kirsher 320e689cf4aSJeff Kirsher err = ldc_put_dring_entry(port->vio.lp, desc, dr->entry_size, 321e689cf4aSJeff Kirsher (index * dr->entry_size), 322e689cf4aSJeff Kirsher dr->cookies, dr->ncookies); 323e689cf4aSJeff Kirsher if (err < 0) 324e689cf4aSJeff Kirsher return err; 325e689cf4aSJeff Kirsher 326e689cf4aSJeff Kirsher return 0; 327e689cf4aSJeff Kirsher } 328e689cf4aSJeff Kirsher 329e689cf4aSJeff Kirsher static int vnet_walk_rx_one(struct vnet_port *port, 330e689cf4aSJeff Kirsher struct vio_dring_state *dr, 331e689cf4aSJeff Kirsher u32 index, int *needs_ack) 332e689cf4aSJeff Kirsher { 333e689cf4aSJeff Kirsher struct vio_net_desc *desc = get_rx_desc(port, dr, index); 334e689cf4aSJeff Kirsher struct vio_driver_state *vio = &port->vio; 335e689cf4aSJeff Kirsher int err; 336e689cf4aSJeff Kirsher 337e689cf4aSJeff Kirsher if (IS_ERR(desc)) 338e689cf4aSJeff Kirsher return PTR_ERR(desc); 339e689cf4aSJeff Kirsher 340e689cf4aSJeff Kirsher viodbg(DATA, "vio_walk_rx_one desc[%02x:%02x:%08x:%08x:%llx:%llx]\n", 341e689cf4aSJeff Kirsher desc->hdr.state, desc->hdr.ack, 342e689cf4aSJeff Kirsher desc->size, desc->ncookies, 343e689cf4aSJeff Kirsher desc->cookies[0].cookie_addr, 344e689cf4aSJeff Kirsher desc->cookies[0].cookie_size); 345e689cf4aSJeff Kirsher 346e689cf4aSJeff Kirsher if (desc->hdr.state != VIO_DESC_READY) 347e689cf4aSJeff Kirsher return 1; 348e689cf4aSJeff Kirsher err = vnet_rx_one(port, desc->size, desc->cookies, desc->ncookies); 349e689cf4aSJeff Kirsher if (err == -ECONNRESET) 350e689cf4aSJeff Kirsher return err; 351e689cf4aSJeff Kirsher desc->hdr.state = VIO_DESC_DONE; 352e689cf4aSJeff Kirsher err = put_rx_desc(port, dr, desc, index); 353e689cf4aSJeff Kirsher if (err < 0) 354e689cf4aSJeff Kirsher return err; 355e689cf4aSJeff Kirsher *needs_ack = desc->hdr.ack; 356e689cf4aSJeff Kirsher return 0; 357e689cf4aSJeff Kirsher } 358e689cf4aSJeff Kirsher 359e689cf4aSJeff Kirsher static int vnet_walk_rx(struct vnet_port *port, struct vio_dring_state *dr, 360e689cf4aSJeff Kirsher u32 start, u32 end) 361e689cf4aSJeff Kirsher { 362e689cf4aSJeff Kirsher struct vio_driver_state *vio = &port->vio; 363e689cf4aSJeff Kirsher int ack_start = -1, ack_end = -1; 364e689cf4aSJeff Kirsher 365e689cf4aSJeff Kirsher end = (end == (u32) -1) ? prev_idx(start, dr) : next_idx(end, dr); 366e689cf4aSJeff Kirsher 367e689cf4aSJeff Kirsher viodbg(DATA, "vnet_walk_rx start[%08x] end[%08x]\n", start, end); 368e689cf4aSJeff Kirsher 369e689cf4aSJeff Kirsher while (start != end) { 370e689cf4aSJeff Kirsher int ack = 0, err = vnet_walk_rx_one(port, dr, start, &ack); 371e689cf4aSJeff Kirsher if (err == -ECONNRESET) 372e689cf4aSJeff Kirsher return err; 373e689cf4aSJeff Kirsher if (err != 0) 374e689cf4aSJeff Kirsher break; 375e689cf4aSJeff Kirsher if (ack_start == -1) 376e689cf4aSJeff Kirsher ack_start = start; 377e689cf4aSJeff Kirsher ack_end = start; 378e689cf4aSJeff Kirsher start = next_idx(start, dr); 379e689cf4aSJeff Kirsher if (ack && start != end) { 380e689cf4aSJeff Kirsher err = vnet_send_ack(port, dr, ack_start, ack_end, 381e689cf4aSJeff Kirsher VIO_DRING_ACTIVE); 382e689cf4aSJeff Kirsher if (err == -ECONNRESET) 383e689cf4aSJeff Kirsher return err; 384e689cf4aSJeff Kirsher ack_start = -1; 385e689cf4aSJeff Kirsher } 386e689cf4aSJeff Kirsher } 387e689cf4aSJeff Kirsher if (unlikely(ack_start == -1)) 388e689cf4aSJeff Kirsher ack_start = ack_end = prev_idx(start, dr); 389e689cf4aSJeff Kirsher return vnet_send_ack(port, dr, ack_start, ack_end, VIO_DRING_STOPPED); 390e689cf4aSJeff Kirsher } 391e689cf4aSJeff Kirsher 392e689cf4aSJeff Kirsher static int vnet_rx(struct vnet_port *port, void *msgbuf) 393e689cf4aSJeff Kirsher { 394e689cf4aSJeff Kirsher struct vio_dring_data *pkt = msgbuf; 395e689cf4aSJeff Kirsher struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_RX_RING]; 396e689cf4aSJeff Kirsher struct vio_driver_state *vio = &port->vio; 397e689cf4aSJeff Kirsher 398e689cf4aSJeff Kirsher viodbg(DATA, "vnet_rx stype_env[%04x] seq[%016llx] rcv_nxt[%016llx]\n", 399e689cf4aSJeff Kirsher pkt->tag.stype_env, pkt->seq, dr->rcv_nxt); 400e689cf4aSJeff Kirsher 401e689cf4aSJeff Kirsher if (unlikely(pkt->tag.stype_env != VIO_DRING_DATA)) 402e689cf4aSJeff Kirsher return 0; 403e689cf4aSJeff Kirsher if (unlikely(pkt->seq != dr->rcv_nxt)) { 404e689cf4aSJeff Kirsher pr_err("RX out of sequence seq[0x%llx] rcv_nxt[0x%llx]\n", 405e689cf4aSJeff Kirsher pkt->seq, dr->rcv_nxt); 406e689cf4aSJeff Kirsher return 0; 407e689cf4aSJeff Kirsher } 408e689cf4aSJeff Kirsher 409e689cf4aSJeff Kirsher dr->rcv_nxt++; 410e689cf4aSJeff Kirsher 411e689cf4aSJeff Kirsher /* XXX Validate pkt->start_idx and pkt->end_idx XXX */ 412e689cf4aSJeff Kirsher 413e689cf4aSJeff Kirsher return vnet_walk_rx(port, dr, pkt->start_idx, pkt->end_idx); 414e689cf4aSJeff Kirsher } 415e689cf4aSJeff Kirsher 416e689cf4aSJeff Kirsher static int idx_is_pending(struct vio_dring_state *dr, u32 end) 417e689cf4aSJeff Kirsher { 418e689cf4aSJeff Kirsher u32 idx = dr->cons; 419e689cf4aSJeff Kirsher int found = 0; 420e689cf4aSJeff Kirsher 421e689cf4aSJeff Kirsher while (idx != dr->prod) { 422e689cf4aSJeff Kirsher if (idx == end) { 423e689cf4aSJeff Kirsher found = 1; 424e689cf4aSJeff Kirsher break; 425e689cf4aSJeff Kirsher } 426e689cf4aSJeff Kirsher idx = next_idx(idx, dr); 427e689cf4aSJeff Kirsher } 428e689cf4aSJeff Kirsher return found; 429e689cf4aSJeff Kirsher } 430e689cf4aSJeff Kirsher 431e689cf4aSJeff Kirsher static int vnet_ack(struct vnet_port *port, void *msgbuf) 432e689cf4aSJeff Kirsher { 433e689cf4aSJeff Kirsher struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING]; 434e689cf4aSJeff Kirsher struct vio_dring_data *pkt = msgbuf; 435e689cf4aSJeff Kirsher struct net_device *dev; 436e689cf4aSJeff Kirsher struct vnet *vp; 437e689cf4aSJeff Kirsher u32 end; 438e689cf4aSJeff Kirsher 439e689cf4aSJeff Kirsher if (unlikely(pkt->tag.stype_env != VIO_DRING_DATA)) 440e689cf4aSJeff Kirsher return 0; 441e689cf4aSJeff Kirsher 442e689cf4aSJeff Kirsher end = pkt->end_idx; 443e689cf4aSJeff Kirsher if (unlikely(!idx_is_pending(dr, end))) 444e689cf4aSJeff Kirsher return 0; 445e689cf4aSJeff Kirsher 446e689cf4aSJeff Kirsher dr->cons = next_idx(end, dr); 447e689cf4aSJeff Kirsher 448e689cf4aSJeff Kirsher vp = port->vp; 449e689cf4aSJeff Kirsher dev = vp->dev; 450e689cf4aSJeff Kirsher if (unlikely(netif_queue_stopped(dev) && 451e689cf4aSJeff Kirsher vnet_tx_dring_avail(dr) >= VNET_TX_WAKEUP_THRESH(dr))) 452e689cf4aSJeff Kirsher return 1; 453e689cf4aSJeff Kirsher 454e689cf4aSJeff Kirsher return 0; 455e689cf4aSJeff Kirsher } 456e689cf4aSJeff Kirsher 457e689cf4aSJeff Kirsher static int vnet_nack(struct vnet_port *port, void *msgbuf) 458e689cf4aSJeff Kirsher { 459e689cf4aSJeff Kirsher /* XXX just reset or similar XXX */ 460e689cf4aSJeff Kirsher return 0; 461e689cf4aSJeff Kirsher } 462e689cf4aSJeff Kirsher 463e689cf4aSJeff Kirsher static int handle_mcast(struct vnet_port *port, void *msgbuf) 464e689cf4aSJeff Kirsher { 465e689cf4aSJeff Kirsher struct vio_net_mcast_info *pkt = msgbuf; 466e689cf4aSJeff Kirsher 467e689cf4aSJeff Kirsher if (pkt->tag.stype != VIO_SUBTYPE_ACK) 468e689cf4aSJeff Kirsher pr_err("%s: Got unexpected MCAST reply [%02x:%02x:%04x:%08x]\n", 469e689cf4aSJeff Kirsher port->vp->dev->name, 470e689cf4aSJeff Kirsher pkt->tag.type, 471e689cf4aSJeff Kirsher pkt->tag.stype, 472e689cf4aSJeff Kirsher pkt->tag.stype_env, 473e689cf4aSJeff Kirsher pkt->tag.sid); 474e689cf4aSJeff Kirsher 475e689cf4aSJeff Kirsher return 0; 476e689cf4aSJeff Kirsher } 477e689cf4aSJeff Kirsher 478e689cf4aSJeff Kirsher static void maybe_tx_wakeup(struct vnet *vp) 479e689cf4aSJeff Kirsher { 480e689cf4aSJeff Kirsher struct net_device *dev = vp->dev; 481e689cf4aSJeff Kirsher 482e689cf4aSJeff Kirsher netif_tx_lock(dev); 483e689cf4aSJeff Kirsher if (likely(netif_queue_stopped(dev))) { 484e689cf4aSJeff Kirsher struct vnet_port *port; 485e689cf4aSJeff Kirsher int wake = 1; 486e689cf4aSJeff Kirsher 487e689cf4aSJeff Kirsher list_for_each_entry(port, &vp->port_list, list) { 488e689cf4aSJeff Kirsher struct vio_dring_state *dr; 489e689cf4aSJeff Kirsher 490e689cf4aSJeff Kirsher dr = &port->vio.drings[VIO_DRIVER_TX_RING]; 491e689cf4aSJeff Kirsher if (vnet_tx_dring_avail(dr) < 492e689cf4aSJeff Kirsher VNET_TX_WAKEUP_THRESH(dr)) { 493e689cf4aSJeff Kirsher wake = 0; 494e689cf4aSJeff Kirsher break; 495e689cf4aSJeff Kirsher } 496e689cf4aSJeff Kirsher } 497e689cf4aSJeff Kirsher if (wake) 498e689cf4aSJeff Kirsher netif_wake_queue(dev); 499e689cf4aSJeff Kirsher } 500e689cf4aSJeff Kirsher netif_tx_unlock(dev); 501e689cf4aSJeff Kirsher } 502e689cf4aSJeff Kirsher 503e689cf4aSJeff Kirsher static void vnet_event(void *arg, int event) 504e689cf4aSJeff Kirsher { 505e689cf4aSJeff Kirsher struct vnet_port *port = arg; 506e689cf4aSJeff Kirsher struct vio_driver_state *vio = &port->vio; 507e689cf4aSJeff Kirsher unsigned long flags; 508e689cf4aSJeff Kirsher int tx_wakeup, err; 509e689cf4aSJeff Kirsher 510e689cf4aSJeff Kirsher spin_lock_irqsave(&vio->lock, flags); 511e689cf4aSJeff Kirsher 512e689cf4aSJeff Kirsher if (unlikely(event == LDC_EVENT_RESET || 513e689cf4aSJeff Kirsher event == LDC_EVENT_UP)) { 514e689cf4aSJeff Kirsher vio_link_state_change(vio, event); 515e689cf4aSJeff Kirsher spin_unlock_irqrestore(&vio->lock, flags); 516e689cf4aSJeff Kirsher 517e689cf4aSJeff Kirsher if (event == LDC_EVENT_RESET) 518e689cf4aSJeff Kirsher vio_port_up(vio); 519e689cf4aSJeff Kirsher return; 520e689cf4aSJeff Kirsher } 521e689cf4aSJeff Kirsher 522e689cf4aSJeff Kirsher if (unlikely(event != LDC_EVENT_DATA_READY)) { 523e689cf4aSJeff Kirsher pr_warning("Unexpected LDC event %d\n", event); 524e689cf4aSJeff Kirsher spin_unlock_irqrestore(&vio->lock, flags); 525e689cf4aSJeff Kirsher return; 526e689cf4aSJeff Kirsher } 527e689cf4aSJeff Kirsher 528e689cf4aSJeff Kirsher tx_wakeup = err = 0; 529e689cf4aSJeff Kirsher while (1) { 530e689cf4aSJeff Kirsher union { 531e689cf4aSJeff Kirsher struct vio_msg_tag tag; 532e689cf4aSJeff Kirsher u64 raw[8]; 533e689cf4aSJeff Kirsher } msgbuf; 534e689cf4aSJeff Kirsher 535e689cf4aSJeff Kirsher err = ldc_read(vio->lp, &msgbuf, sizeof(msgbuf)); 536e689cf4aSJeff Kirsher if (unlikely(err < 0)) { 537e689cf4aSJeff Kirsher if (err == -ECONNRESET) 538e689cf4aSJeff Kirsher vio_conn_reset(vio); 539e689cf4aSJeff Kirsher break; 540e689cf4aSJeff Kirsher } 541e689cf4aSJeff Kirsher if (err == 0) 542e689cf4aSJeff Kirsher break; 543e689cf4aSJeff Kirsher viodbg(DATA, "TAG [%02x:%02x:%04x:%08x]\n", 544e689cf4aSJeff Kirsher msgbuf.tag.type, 545e689cf4aSJeff Kirsher msgbuf.tag.stype, 546e689cf4aSJeff Kirsher msgbuf.tag.stype_env, 547e689cf4aSJeff Kirsher msgbuf.tag.sid); 548e689cf4aSJeff Kirsher err = vio_validate_sid(vio, &msgbuf.tag); 549e689cf4aSJeff Kirsher if (err < 0) 550e689cf4aSJeff Kirsher break; 551e689cf4aSJeff Kirsher 552e689cf4aSJeff Kirsher if (likely(msgbuf.tag.type == VIO_TYPE_DATA)) { 553e689cf4aSJeff Kirsher if (msgbuf.tag.stype == VIO_SUBTYPE_INFO) { 554e689cf4aSJeff Kirsher err = vnet_rx(port, &msgbuf); 555e689cf4aSJeff Kirsher } else if (msgbuf.tag.stype == VIO_SUBTYPE_ACK) { 556e689cf4aSJeff Kirsher err = vnet_ack(port, &msgbuf); 557e689cf4aSJeff Kirsher if (err > 0) 558e689cf4aSJeff Kirsher tx_wakeup |= err; 559e689cf4aSJeff Kirsher } else if (msgbuf.tag.stype == VIO_SUBTYPE_NACK) { 560e689cf4aSJeff Kirsher err = vnet_nack(port, &msgbuf); 561e689cf4aSJeff Kirsher } 562e689cf4aSJeff Kirsher } else if (msgbuf.tag.type == VIO_TYPE_CTRL) { 563e689cf4aSJeff Kirsher if (msgbuf.tag.stype_env == VNET_MCAST_INFO) 564e689cf4aSJeff Kirsher err = handle_mcast(port, &msgbuf); 565e689cf4aSJeff Kirsher else 566e689cf4aSJeff Kirsher err = vio_control_pkt_engine(vio, &msgbuf); 567e689cf4aSJeff Kirsher if (err) 568e689cf4aSJeff Kirsher break; 569e689cf4aSJeff Kirsher } else { 570e689cf4aSJeff Kirsher err = vnet_handle_unknown(port, &msgbuf); 571e689cf4aSJeff Kirsher } 572e689cf4aSJeff Kirsher if (err == -ECONNRESET) 573e689cf4aSJeff Kirsher break; 574e689cf4aSJeff Kirsher } 575e689cf4aSJeff Kirsher spin_unlock(&vio->lock); 576e689cf4aSJeff Kirsher if (unlikely(tx_wakeup && err != -ECONNRESET)) 577e689cf4aSJeff Kirsher maybe_tx_wakeup(port->vp); 578e689cf4aSJeff Kirsher local_irq_restore(flags); 579e689cf4aSJeff Kirsher } 580e689cf4aSJeff Kirsher 581e689cf4aSJeff Kirsher static int __vnet_tx_trigger(struct vnet_port *port) 582e689cf4aSJeff Kirsher { 583e689cf4aSJeff Kirsher struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING]; 584e689cf4aSJeff Kirsher struct vio_dring_data hdr = { 585e689cf4aSJeff Kirsher .tag = { 586e689cf4aSJeff Kirsher .type = VIO_TYPE_DATA, 587e689cf4aSJeff Kirsher .stype = VIO_SUBTYPE_INFO, 588e689cf4aSJeff Kirsher .stype_env = VIO_DRING_DATA, 589e689cf4aSJeff Kirsher .sid = vio_send_sid(&port->vio), 590e689cf4aSJeff Kirsher }, 591e689cf4aSJeff Kirsher .dring_ident = dr->ident, 592e689cf4aSJeff Kirsher .start_idx = dr->prod, 593e689cf4aSJeff Kirsher .end_idx = (u32) -1, 594e689cf4aSJeff Kirsher }; 595e689cf4aSJeff Kirsher int err, delay; 596e689cf4aSJeff Kirsher 597e689cf4aSJeff Kirsher hdr.seq = dr->snd_nxt; 598e689cf4aSJeff Kirsher delay = 1; 599e689cf4aSJeff Kirsher do { 600e689cf4aSJeff Kirsher err = vio_ldc_send(&port->vio, &hdr, sizeof(hdr)); 601e689cf4aSJeff Kirsher if (err > 0) { 602e689cf4aSJeff Kirsher dr->snd_nxt++; 603e689cf4aSJeff Kirsher break; 604e689cf4aSJeff Kirsher } 605e689cf4aSJeff Kirsher udelay(delay); 606e689cf4aSJeff Kirsher if ((delay <<= 1) > 128) 607e689cf4aSJeff Kirsher delay = 128; 608e689cf4aSJeff Kirsher } while (err == -EAGAIN); 609e689cf4aSJeff Kirsher 610e689cf4aSJeff Kirsher return err; 611e689cf4aSJeff Kirsher } 612e689cf4aSJeff Kirsher 613e689cf4aSJeff Kirsher struct vnet_port *__tx_port_find(struct vnet *vp, struct sk_buff *skb) 614e689cf4aSJeff Kirsher { 615e689cf4aSJeff Kirsher unsigned int hash = vnet_hashfn(skb->data); 616e689cf4aSJeff Kirsher struct hlist_head *hp = &vp->port_hash[hash]; 617e689cf4aSJeff Kirsher struct hlist_node *n; 618e689cf4aSJeff Kirsher struct vnet_port *port; 619e689cf4aSJeff Kirsher 620e689cf4aSJeff Kirsher hlist_for_each_entry(port, n, hp, hash) { 6212e42e474SJoe Perches if (ether_addr_equal(port->raddr, skb->data)) 622e689cf4aSJeff Kirsher return port; 623e689cf4aSJeff Kirsher } 624e689cf4aSJeff Kirsher port = NULL; 625e689cf4aSJeff Kirsher if (!list_empty(&vp->port_list)) 626e689cf4aSJeff Kirsher port = list_entry(vp->port_list.next, struct vnet_port, list); 627e689cf4aSJeff Kirsher 628e689cf4aSJeff Kirsher return port; 629e689cf4aSJeff Kirsher } 630e689cf4aSJeff Kirsher 631e689cf4aSJeff Kirsher struct vnet_port *tx_port_find(struct vnet *vp, struct sk_buff *skb) 632e689cf4aSJeff Kirsher { 633e689cf4aSJeff Kirsher struct vnet_port *ret; 634e689cf4aSJeff Kirsher unsigned long flags; 635e689cf4aSJeff Kirsher 636e689cf4aSJeff Kirsher spin_lock_irqsave(&vp->lock, flags); 637e689cf4aSJeff Kirsher ret = __tx_port_find(vp, skb); 638e689cf4aSJeff Kirsher spin_unlock_irqrestore(&vp->lock, flags); 639e689cf4aSJeff Kirsher 640e689cf4aSJeff Kirsher return ret; 641e689cf4aSJeff Kirsher } 642e689cf4aSJeff Kirsher 643e689cf4aSJeff Kirsher static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev) 644e689cf4aSJeff Kirsher { 645e689cf4aSJeff Kirsher struct vnet *vp = netdev_priv(dev); 646e689cf4aSJeff Kirsher struct vnet_port *port = tx_port_find(vp, skb); 647e689cf4aSJeff Kirsher struct vio_dring_state *dr; 648e689cf4aSJeff Kirsher struct vio_net_desc *d; 649e689cf4aSJeff Kirsher unsigned long flags; 650e689cf4aSJeff Kirsher unsigned int len; 651e689cf4aSJeff Kirsher void *tx_buf; 652e689cf4aSJeff Kirsher int i, err; 653e689cf4aSJeff Kirsher 654e689cf4aSJeff Kirsher if (unlikely(!port)) 655e689cf4aSJeff Kirsher goto out_dropped; 656e689cf4aSJeff Kirsher 657e689cf4aSJeff Kirsher spin_lock_irqsave(&port->vio.lock, flags); 658e689cf4aSJeff Kirsher 659e689cf4aSJeff Kirsher dr = &port->vio.drings[VIO_DRIVER_TX_RING]; 660e689cf4aSJeff Kirsher if (unlikely(vnet_tx_dring_avail(dr) < 2)) { 661e689cf4aSJeff Kirsher if (!netif_queue_stopped(dev)) { 662e689cf4aSJeff Kirsher netif_stop_queue(dev); 663e689cf4aSJeff Kirsher 664e689cf4aSJeff Kirsher /* This is a hard error, log it. */ 665e689cf4aSJeff Kirsher netdev_err(dev, "BUG! Tx Ring full when queue awake!\n"); 666e689cf4aSJeff Kirsher dev->stats.tx_errors++; 667e689cf4aSJeff Kirsher } 668e689cf4aSJeff Kirsher spin_unlock_irqrestore(&port->vio.lock, flags); 669e689cf4aSJeff Kirsher return NETDEV_TX_BUSY; 670e689cf4aSJeff Kirsher } 671e689cf4aSJeff Kirsher 672e689cf4aSJeff Kirsher d = vio_dring_cur(dr); 673e689cf4aSJeff Kirsher 674e689cf4aSJeff Kirsher tx_buf = port->tx_bufs[dr->prod].buf; 675e689cf4aSJeff Kirsher skb_copy_from_linear_data(skb, tx_buf + VNET_PACKET_SKIP, skb->len); 676e689cf4aSJeff Kirsher 677e689cf4aSJeff Kirsher len = skb->len; 678e689cf4aSJeff Kirsher if (len < ETH_ZLEN) { 679e689cf4aSJeff Kirsher len = ETH_ZLEN; 680e689cf4aSJeff Kirsher memset(tx_buf+VNET_PACKET_SKIP+skb->len, 0, len - skb->len); 681e689cf4aSJeff Kirsher } 682e689cf4aSJeff Kirsher 683e689cf4aSJeff Kirsher d->hdr.ack = VIO_ACK_ENABLE; 684e689cf4aSJeff Kirsher d->size = len; 685e689cf4aSJeff Kirsher d->ncookies = port->tx_bufs[dr->prod].ncookies; 686e689cf4aSJeff Kirsher for (i = 0; i < d->ncookies; i++) 687e689cf4aSJeff Kirsher d->cookies[i] = port->tx_bufs[dr->prod].cookies[i]; 688e689cf4aSJeff Kirsher 689e689cf4aSJeff Kirsher /* This has to be a non-SMP write barrier because we are writing 690e689cf4aSJeff Kirsher * to memory which is shared with the peer LDOM. 691e689cf4aSJeff Kirsher */ 692e689cf4aSJeff Kirsher wmb(); 693e689cf4aSJeff Kirsher 694e689cf4aSJeff Kirsher d->hdr.state = VIO_DESC_READY; 695e689cf4aSJeff Kirsher 696e689cf4aSJeff Kirsher err = __vnet_tx_trigger(port); 697e689cf4aSJeff Kirsher if (unlikely(err < 0)) { 698e689cf4aSJeff Kirsher netdev_info(dev, "TX trigger error %d\n", err); 699e689cf4aSJeff Kirsher d->hdr.state = VIO_DESC_FREE; 700e689cf4aSJeff Kirsher dev->stats.tx_carrier_errors++; 701e689cf4aSJeff Kirsher goto out_dropped_unlock; 702e689cf4aSJeff Kirsher } 703e689cf4aSJeff Kirsher 704e689cf4aSJeff Kirsher dev->stats.tx_packets++; 705e689cf4aSJeff Kirsher dev->stats.tx_bytes += skb->len; 706e689cf4aSJeff Kirsher 707e689cf4aSJeff Kirsher dr->prod = (dr->prod + 1) & (VNET_TX_RING_SIZE - 1); 708e689cf4aSJeff Kirsher if (unlikely(vnet_tx_dring_avail(dr) < 2)) { 709e689cf4aSJeff Kirsher netif_stop_queue(dev); 710e689cf4aSJeff Kirsher if (vnet_tx_dring_avail(dr) > VNET_TX_WAKEUP_THRESH(dr)) 711e689cf4aSJeff Kirsher netif_wake_queue(dev); 712e689cf4aSJeff Kirsher } 713e689cf4aSJeff Kirsher 714e689cf4aSJeff Kirsher spin_unlock_irqrestore(&port->vio.lock, flags); 715e689cf4aSJeff Kirsher 716e689cf4aSJeff Kirsher dev_kfree_skb(skb); 717e689cf4aSJeff Kirsher 718e689cf4aSJeff Kirsher return NETDEV_TX_OK; 719e689cf4aSJeff Kirsher 720e689cf4aSJeff Kirsher out_dropped_unlock: 721e689cf4aSJeff Kirsher spin_unlock_irqrestore(&port->vio.lock, flags); 722e689cf4aSJeff Kirsher 723e689cf4aSJeff Kirsher out_dropped: 724e689cf4aSJeff Kirsher dev_kfree_skb(skb); 725e689cf4aSJeff Kirsher dev->stats.tx_dropped++; 726e689cf4aSJeff Kirsher return NETDEV_TX_OK; 727e689cf4aSJeff Kirsher } 728e689cf4aSJeff Kirsher 729e689cf4aSJeff Kirsher static void vnet_tx_timeout(struct net_device *dev) 730e689cf4aSJeff Kirsher { 731e689cf4aSJeff Kirsher /* XXX Implement me XXX */ 732e689cf4aSJeff Kirsher } 733e689cf4aSJeff Kirsher 734e689cf4aSJeff Kirsher static int vnet_open(struct net_device *dev) 735e689cf4aSJeff Kirsher { 736e689cf4aSJeff Kirsher netif_carrier_on(dev); 737e689cf4aSJeff Kirsher netif_start_queue(dev); 738e689cf4aSJeff Kirsher 739e689cf4aSJeff Kirsher return 0; 740e689cf4aSJeff Kirsher } 741e689cf4aSJeff Kirsher 742e689cf4aSJeff Kirsher static int vnet_close(struct net_device *dev) 743e689cf4aSJeff Kirsher { 744e689cf4aSJeff Kirsher netif_stop_queue(dev); 745e689cf4aSJeff Kirsher netif_carrier_off(dev); 746e689cf4aSJeff Kirsher 747e689cf4aSJeff Kirsher return 0; 748e689cf4aSJeff Kirsher } 749e689cf4aSJeff Kirsher 750e689cf4aSJeff Kirsher static struct vnet_mcast_entry *__vnet_mc_find(struct vnet *vp, u8 *addr) 751e689cf4aSJeff Kirsher { 752e689cf4aSJeff Kirsher struct vnet_mcast_entry *m; 753e689cf4aSJeff Kirsher 754e689cf4aSJeff Kirsher for (m = vp->mcast_list; m; m = m->next) { 755e689cf4aSJeff Kirsher if (!memcmp(m->addr, addr, ETH_ALEN)) 756e689cf4aSJeff Kirsher return m; 757e689cf4aSJeff Kirsher } 758e689cf4aSJeff Kirsher return NULL; 759e689cf4aSJeff Kirsher } 760e689cf4aSJeff Kirsher 761e689cf4aSJeff Kirsher static void __update_mc_list(struct vnet *vp, struct net_device *dev) 762e689cf4aSJeff Kirsher { 763e689cf4aSJeff Kirsher struct netdev_hw_addr *ha; 764e689cf4aSJeff Kirsher 765e689cf4aSJeff Kirsher netdev_for_each_mc_addr(ha, dev) { 766e689cf4aSJeff Kirsher struct vnet_mcast_entry *m; 767e689cf4aSJeff Kirsher 768e689cf4aSJeff Kirsher m = __vnet_mc_find(vp, ha->addr); 769e689cf4aSJeff Kirsher if (m) { 770e689cf4aSJeff Kirsher m->hit = 1; 771e689cf4aSJeff Kirsher continue; 772e689cf4aSJeff Kirsher } 773e689cf4aSJeff Kirsher 774e689cf4aSJeff Kirsher if (!m) { 775e689cf4aSJeff Kirsher m = kzalloc(sizeof(*m), GFP_ATOMIC); 776e689cf4aSJeff Kirsher if (!m) 777e689cf4aSJeff Kirsher continue; 778e689cf4aSJeff Kirsher memcpy(m->addr, ha->addr, ETH_ALEN); 779e689cf4aSJeff Kirsher m->hit = 1; 780e689cf4aSJeff Kirsher 781e689cf4aSJeff Kirsher m->next = vp->mcast_list; 782e689cf4aSJeff Kirsher vp->mcast_list = m; 783e689cf4aSJeff Kirsher } 784e689cf4aSJeff Kirsher } 785e689cf4aSJeff Kirsher } 786e689cf4aSJeff Kirsher 787e689cf4aSJeff Kirsher static void __send_mc_list(struct vnet *vp, struct vnet_port *port) 788e689cf4aSJeff Kirsher { 789e689cf4aSJeff Kirsher struct vio_net_mcast_info info; 790e689cf4aSJeff Kirsher struct vnet_mcast_entry *m, **pp; 791e689cf4aSJeff Kirsher int n_addrs; 792e689cf4aSJeff Kirsher 793e689cf4aSJeff Kirsher memset(&info, 0, sizeof(info)); 794e689cf4aSJeff Kirsher 795e689cf4aSJeff Kirsher info.tag.type = VIO_TYPE_CTRL; 796e689cf4aSJeff Kirsher info.tag.stype = VIO_SUBTYPE_INFO; 797e689cf4aSJeff Kirsher info.tag.stype_env = VNET_MCAST_INFO; 798e689cf4aSJeff Kirsher info.tag.sid = vio_send_sid(&port->vio); 799e689cf4aSJeff Kirsher info.set = 1; 800e689cf4aSJeff Kirsher 801e689cf4aSJeff Kirsher n_addrs = 0; 802e689cf4aSJeff Kirsher for (m = vp->mcast_list; m; m = m->next) { 803e689cf4aSJeff Kirsher if (m->sent) 804e689cf4aSJeff Kirsher continue; 805e689cf4aSJeff Kirsher m->sent = 1; 806e689cf4aSJeff Kirsher memcpy(&info.mcast_addr[n_addrs * ETH_ALEN], 807e689cf4aSJeff Kirsher m->addr, ETH_ALEN); 808e689cf4aSJeff Kirsher if (++n_addrs == VNET_NUM_MCAST) { 809e689cf4aSJeff Kirsher info.count = n_addrs; 810e689cf4aSJeff Kirsher 811e689cf4aSJeff Kirsher (void) vio_ldc_send(&port->vio, &info, 812e689cf4aSJeff Kirsher sizeof(info)); 813e689cf4aSJeff Kirsher n_addrs = 0; 814e689cf4aSJeff Kirsher } 815e689cf4aSJeff Kirsher } 816e689cf4aSJeff Kirsher if (n_addrs) { 817e689cf4aSJeff Kirsher info.count = n_addrs; 818e689cf4aSJeff Kirsher (void) vio_ldc_send(&port->vio, &info, sizeof(info)); 819e689cf4aSJeff Kirsher } 820e689cf4aSJeff Kirsher 821e689cf4aSJeff Kirsher info.set = 0; 822e689cf4aSJeff Kirsher 823e689cf4aSJeff Kirsher n_addrs = 0; 824e689cf4aSJeff Kirsher pp = &vp->mcast_list; 825e689cf4aSJeff Kirsher while ((m = *pp) != NULL) { 826e689cf4aSJeff Kirsher if (m->hit) { 827e689cf4aSJeff Kirsher m->hit = 0; 828e689cf4aSJeff Kirsher pp = &m->next; 829e689cf4aSJeff Kirsher continue; 830e689cf4aSJeff Kirsher } 831e689cf4aSJeff Kirsher 832e689cf4aSJeff Kirsher memcpy(&info.mcast_addr[n_addrs * ETH_ALEN], 833e689cf4aSJeff Kirsher m->addr, ETH_ALEN); 834e689cf4aSJeff Kirsher if (++n_addrs == VNET_NUM_MCAST) { 835e689cf4aSJeff Kirsher info.count = n_addrs; 836e689cf4aSJeff Kirsher (void) vio_ldc_send(&port->vio, &info, 837e689cf4aSJeff Kirsher sizeof(info)); 838e689cf4aSJeff Kirsher n_addrs = 0; 839e689cf4aSJeff Kirsher } 840e689cf4aSJeff Kirsher 841e689cf4aSJeff Kirsher *pp = m->next; 842e689cf4aSJeff Kirsher kfree(m); 843e689cf4aSJeff Kirsher } 844e689cf4aSJeff Kirsher if (n_addrs) { 845e689cf4aSJeff Kirsher info.count = n_addrs; 846e689cf4aSJeff Kirsher (void) vio_ldc_send(&port->vio, &info, sizeof(info)); 847e689cf4aSJeff Kirsher } 848e689cf4aSJeff Kirsher } 849e689cf4aSJeff Kirsher 850e689cf4aSJeff Kirsher static void vnet_set_rx_mode(struct net_device *dev) 851e689cf4aSJeff Kirsher { 852e689cf4aSJeff Kirsher struct vnet *vp = netdev_priv(dev); 853e689cf4aSJeff Kirsher struct vnet_port *port; 854e689cf4aSJeff Kirsher unsigned long flags; 855e689cf4aSJeff Kirsher 856e689cf4aSJeff Kirsher spin_lock_irqsave(&vp->lock, flags); 857e689cf4aSJeff Kirsher if (!list_empty(&vp->port_list)) { 858e689cf4aSJeff Kirsher port = list_entry(vp->port_list.next, struct vnet_port, list); 859e689cf4aSJeff Kirsher 860e689cf4aSJeff Kirsher if (port->switch_port) { 861e689cf4aSJeff Kirsher __update_mc_list(vp, dev); 862e689cf4aSJeff Kirsher __send_mc_list(vp, port); 863e689cf4aSJeff Kirsher } 864e689cf4aSJeff Kirsher } 865e689cf4aSJeff Kirsher spin_unlock_irqrestore(&vp->lock, flags); 866e689cf4aSJeff Kirsher } 867e689cf4aSJeff Kirsher 868e689cf4aSJeff Kirsher static int vnet_change_mtu(struct net_device *dev, int new_mtu) 869e689cf4aSJeff Kirsher { 870e689cf4aSJeff Kirsher if (new_mtu != ETH_DATA_LEN) 871e689cf4aSJeff Kirsher return -EINVAL; 872e689cf4aSJeff Kirsher 873e689cf4aSJeff Kirsher dev->mtu = new_mtu; 874e689cf4aSJeff Kirsher return 0; 875e689cf4aSJeff Kirsher } 876e689cf4aSJeff Kirsher 877e689cf4aSJeff Kirsher static int vnet_set_mac_addr(struct net_device *dev, void *p) 878e689cf4aSJeff Kirsher { 879e689cf4aSJeff Kirsher return -EINVAL; 880e689cf4aSJeff Kirsher } 881e689cf4aSJeff Kirsher 882e689cf4aSJeff Kirsher static void vnet_get_drvinfo(struct net_device *dev, 883e689cf4aSJeff Kirsher struct ethtool_drvinfo *info) 884e689cf4aSJeff Kirsher { 885e689cf4aSJeff Kirsher strcpy(info->driver, DRV_MODULE_NAME); 886e689cf4aSJeff Kirsher strcpy(info->version, DRV_MODULE_VERSION); 887e689cf4aSJeff Kirsher } 888e689cf4aSJeff Kirsher 889e689cf4aSJeff Kirsher static u32 vnet_get_msglevel(struct net_device *dev) 890e689cf4aSJeff Kirsher { 891e689cf4aSJeff Kirsher struct vnet *vp = netdev_priv(dev); 892e689cf4aSJeff Kirsher return vp->msg_enable; 893e689cf4aSJeff Kirsher } 894e689cf4aSJeff Kirsher 895e689cf4aSJeff Kirsher static void vnet_set_msglevel(struct net_device *dev, u32 value) 896e689cf4aSJeff Kirsher { 897e689cf4aSJeff Kirsher struct vnet *vp = netdev_priv(dev); 898e689cf4aSJeff Kirsher vp->msg_enable = value; 899e689cf4aSJeff Kirsher } 900e689cf4aSJeff Kirsher 901e689cf4aSJeff Kirsher static const struct ethtool_ops vnet_ethtool_ops = { 902e689cf4aSJeff Kirsher .get_drvinfo = vnet_get_drvinfo, 903e689cf4aSJeff Kirsher .get_msglevel = vnet_get_msglevel, 904e689cf4aSJeff Kirsher .set_msglevel = vnet_set_msglevel, 905e689cf4aSJeff Kirsher .get_link = ethtool_op_get_link, 906e689cf4aSJeff Kirsher }; 907e689cf4aSJeff Kirsher 908e689cf4aSJeff Kirsher static void vnet_port_free_tx_bufs(struct vnet_port *port) 909e689cf4aSJeff Kirsher { 910e689cf4aSJeff Kirsher struct vio_dring_state *dr; 911e689cf4aSJeff Kirsher int i; 912e689cf4aSJeff Kirsher 913e689cf4aSJeff Kirsher dr = &port->vio.drings[VIO_DRIVER_TX_RING]; 914e689cf4aSJeff Kirsher if (dr->base) { 915e689cf4aSJeff Kirsher ldc_free_exp_dring(port->vio.lp, dr->base, 916e689cf4aSJeff Kirsher (dr->entry_size * dr->num_entries), 917e689cf4aSJeff Kirsher dr->cookies, dr->ncookies); 918e689cf4aSJeff Kirsher dr->base = NULL; 919e689cf4aSJeff Kirsher dr->entry_size = 0; 920e689cf4aSJeff Kirsher dr->num_entries = 0; 921e689cf4aSJeff Kirsher dr->pending = 0; 922e689cf4aSJeff Kirsher dr->ncookies = 0; 923e689cf4aSJeff Kirsher } 924e689cf4aSJeff Kirsher 925e689cf4aSJeff Kirsher for (i = 0; i < VNET_TX_RING_SIZE; i++) { 926e689cf4aSJeff Kirsher void *buf = port->tx_bufs[i].buf; 927e689cf4aSJeff Kirsher 928e689cf4aSJeff Kirsher if (!buf) 929e689cf4aSJeff Kirsher continue; 930e689cf4aSJeff Kirsher 931e689cf4aSJeff Kirsher ldc_unmap(port->vio.lp, 932e689cf4aSJeff Kirsher port->tx_bufs[i].cookies, 933e689cf4aSJeff Kirsher port->tx_bufs[i].ncookies); 934e689cf4aSJeff Kirsher 935e689cf4aSJeff Kirsher kfree(buf); 936e689cf4aSJeff Kirsher port->tx_bufs[i].buf = NULL; 937e689cf4aSJeff Kirsher } 938e689cf4aSJeff Kirsher } 939e689cf4aSJeff Kirsher 940f73d12bdSBill Pemberton static int vnet_port_alloc_tx_bufs(struct vnet_port *port) 941e689cf4aSJeff Kirsher { 942e689cf4aSJeff Kirsher struct vio_dring_state *dr; 943e689cf4aSJeff Kirsher unsigned long len; 944e689cf4aSJeff Kirsher int i, err, ncookies; 945e689cf4aSJeff Kirsher void *dring; 946e689cf4aSJeff Kirsher 947e689cf4aSJeff Kirsher for (i = 0; i < VNET_TX_RING_SIZE; i++) { 948e689cf4aSJeff Kirsher void *buf = kzalloc(ETH_FRAME_LEN + 8, GFP_KERNEL); 949e689cf4aSJeff Kirsher int map_len = (ETH_FRAME_LEN + 7) & ~7; 950e689cf4aSJeff Kirsher 951e689cf4aSJeff Kirsher err = -ENOMEM; 952e404decbSJoe Perches if (!buf) 953e689cf4aSJeff Kirsher goto err_out; 954e404decbSJoe Perches 955e689cf4aSJeff Kirsher err = -EFAULT; 956e689cf4aSJeff Kirsher if ((unsigned long)buf & (8UL - 1)) { 957e689cf4aSJeff Kirsher pr_err("TX buffer misaligned\n"); 958e689cf4aSJeff Kirsher kfree(buf); 959e689cf4aSJeff Kirsher goto err_out; 960e689cf4aSJeff Kirsher } 961e689cf4aSJeff Kirsher 962e689cf4aSJeff Kirsher err = ldc_map_single(port->vio.lp, buf, map_len, 963e689cf4aSJeff Kirsher port->tx_bufs[i].cookies, 2, 964e689cf4aSJeff Kirsher (LDC_MAP_SHADOW | 965e689cf4aSJeff Kirsher LDC_MAP_DIRECT | 966e689cf4aSJeff Kirsher LDC_MAP_RW)); 967e689cf4aSJeff Kirsher if (err < 0) { 968e689cf4aSJeff Kirsher kfree(buf); 969e689cf4aSJeff Kirsher goto err_out; 970e689cf4aSJeff Kirsher } 971e689cf4aSJeff Kirsher port->tx_bufs[i].buf = buf; 972e689cf4aSJeff Kirsher port->tx_bufs[i].ncookies = err; 973e689cf4aSJeff Kirsher } 974e689cf4aSJeff Kirsher 975e689cf4aSJeff Kirsher dr = &port->vio.drings[VIO_DRIVER_TX_RING]; 976e689cf4aSJeff Kirsher 977e689cf4aSJeff Kirsher len = (VNET_TX_RING_SIZE * 978e689cf4aSJeff Kirsher (sizeof(struct vio_net_desc) + 979e689cf4aSJeff Kirsher (sizeof(struct ldc_trans_cookie) * 2))); 980e689cf4aSJeff Kirsher 981e689cf4aSJeff Kirsher ncookies = VIO_MAX_RING_COOKIES; 982e689cf4aSJeff Kirsher dring = ldc_alloc_exp_dring(port->vio.lp, len, 983e689cf4aSJeff Kirsher dr->cookies, &ncookies, 984e689cf4aSJeff Kirsher (LDC_MAP_SHADOW | 985e689cf4aSJeff Kirsher LDC_MAP_DIRECT | 986e689cf4aSJeff Kirsher LDC_MAP_RW)); 987e689cf4aSJeff Kirsher if (IS_ERR(dring)) { 988e689cf4aSJeff Kirsher err = PTR_ERR(dring); 989e689cf4aSJeff Kirsher goto err_out; 990e689cf4aSJeff Kirsher } 991e689cf4aSJeff Kirsher 992e689cf4aSJeff Kirsher dr->base = dring; 993e689cf4aSJeff Kirsher dr->entry_size = (sizeof(struct vio_net_desc) + 994e689cf4aSJeff Kirsher (sizeof(struct ldc_trans_cookie) * 2)); 995e689cf4aSJeff Kirsher dr->num_entries = VNET_TX_RING_SIZE; 996e689cf4aSJeff Kirsher dr->prod = dr->cons = 0; 997e689cf4aSJeff Kirsher dr->pending = VNET_TX_RING_SIZE; 998e689cf4aSJeff Kirsher dr->ncookies = ncookies; 999e689cf4aSJeff Kirsher 1000e689cf4aSJeff Kirsher return 0; 1001e689cf4aSJeff Kirsher 1002e689cf4aSJeff Kirsher err_out: 1003e689cf4aSJeff Kirsher vnet_port_free_tx_bufs(port); 1004e689cf4aSJeff Kirsher 1005e689cf4aSJeff Kirsher return err; 1006e689cf4aSJeff Kirsher } 1007e689cf4aSJeff Kirsher 1008e689cf4aSJeff Kirsher static LIST_HEAD(vnet_list); 1009e689cf4aSJeff Kirsher static DEFINE_MUTEX(vnet_list_mutex); 1010e689cf4aSJeff Kirsher 1011e689cf4aSJeff Kirsher static const struct net_device_ops vnet_ops = { 1012e689cf4aSJeff Kirsher .ndo_open = vnet_open, 1013e689cf4aSJeff Kirsher .ndo_stop = vnet_close, 1014afc4b13dSJiri Pirko .ndo_set_rx_mode = vnet_set_rx_mode, 1015e689cf4aSJeff Kirsher .ndo_set_mac_address = vnet_set_mac_addr, 1016e689cf4aSJeff Kirsher .ndo_validate_addr = eth_validate_addr, 1017e689cf4aSJeff Kirsher .ndo_tx_timeout = vnet_tx_timeout, 1018e689cf4aSJeff Kirsher .ndo_change_mtu = vnet_change_mtu, 1019e689cf4aSJeff Kirsher .ndo_start_xmit = vnet_start_xmit, 1020e689cf4aSJeff Kirsher }; 1021e689cf4aSJeff Kirsher 1022f73d12bdSBill Pemberton static struct vnet *vnet_new(const u64 *local_mac) 1023e689cf4aSJeff Kirsher { 1024e689cf4aSJeff Kirsher struct net_device *dev; 1025e689cf4aSJeff Kirsher struct vnet *vp; 1026e689cf4aSJeff Kirsher int err, i; 1027e689cf4aSJeff Kirsher 1028e689cf4aSJeff Kirsher dev = alloc_etherdev(sizeof(*vp)); 102941de8d4cSJoe Perches if (!dev) 1030e689cf4aSJeff Kirsher return ERR_PTR(-ENOMEM); 1031e689cf4aSJeff Kirsher 1032e689cf4aSJeff Kirsher for (i = 0; i < ETH_ALEN; i++) 1033e689cf4aSJeff Kirsher dev->dev_addr[i] = (*local_mac >> (5 - i) * 8) & 0xff; 1034e689cf4aSJeff Kirsher 1035e689cf4aSJeff Kirsher memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); 1036e689cf4aSJeff Kirsher 1037e689cf4aSJeff Kirsher vp = netdev_priv(dev); 1038e689cf4aSJeff Kirsher 1039e689cf4aSJeff Kirsher spin_lock_init(&vp->lock); 1040e689cf4aSJeff Kirsher vp->dev = dev; 1041e689cf4aSJeff Kirsher 1042e689cf4aSJeff Kirsher INIT_LIST_HEAD(&vp->port_list); 1043e689cf4aSJeff Kirsher for (i = 0; i < VNET_PORT_HASH_SIZE; i++) 1044e689cf4aSJeff Kirsher INIT_HLIST_HEAD(&vp->port_hash[i]); 1045e689cf4aSJeff Kirsher INIT_LIST_HEAD(&vp->list); 1046e689cf4aSJeff Kirsher vp->local_mac = *local_mac; 1047e689cf4aSJeff Kirsher 1048e689cf4aSJeff Kirsher dev->netdev_ops = &vnet_ops; 1049e689cf4aSJeff Kirsher dev->ethtool_ops = &vnet_ethtool_ops; 1050e689cf4aSJeff Kirsher dev->watchdog_timeo = VNET_TX_TIMEOUT; 1051e689cf4aSJeff Kirsher 1052e689cf4aSJeff Kirsher err = register_netdev(dev); 1053e689cf4aSJeff Kirsher if (err) { 1054e689cf4aSJeff Kirsher pr_err("Cannot register net device, aborting\n"); 1055e689cf4aSJeff Kirsher goto err_out_free_dev; 1056e689cf4aSJeff Kirsher } 1057e689cf4aSJeff Kirsher 1058e689cf4aSJeff Kirsher netdev_info(dev, "Sun LDOM vnet %pM\n", dev->dev_addr); 1059e689cf4aSJeff Kirsher 1060e689cf4aSJeff Kirsher list_add(&vp->list, &vnet_list); 1061e689cf4aSJeff Kirsher 1062e689cf4aSJeff Kirsher return vp; 1063e689cf4aSJeff Kirsher 1064e689cf4aSJeff Kirsher err_out_free_dev: 1065e689cf4aSJeff Kirsher free_netdev(dev); 1066e689cf4aSJeff Kirsher 1067e689cf4aSJeff Kirsher return ERR_PTR(err); 1068e689cf4aSJeff Kirsher } 1069e689cf4aSJeff Kirsher 1070f73d12bdSBill Pemberton static struct vnet *vnet_find_or_create(const u64 *local_mac) 1071e689cf4aSJeff Kirsher { 1072e689cf4aSJeff Kirsher struct vnet *iter, *vp; 1073e689cf4aSJeff Kirsher 1074e689cf4aSJeff Kirsher mutex_lock(&vnet_list_mutex); 1075e689cf4aSJeff Kirsher vp = NULL; 1076e689cf4aSJeff Kirsher list_for_each_entry(iter, &vnet_list, list) { 1077e689cf4aSJeff Kirsher if (iter->local_mac == *local_mac) { 1078e689cf4aSJeff Kirsher vp = iter; 1079e689cf4aSJeff Kirsher break; 1080e689cf4aSJeff Kirsher } 1081e689cf4aSJeff Kirsher } 1082e689cf4aSJeff Kirsher if (!vp) 1083e689cf4aSJeff Kirsher vp = vnet_new(local_mac); 1084e689cf4aSJeff Kirsher mutex_unlock(&vnet_list_mutex); 1085e689cf4aSJeff Kirsher 1086e689cf4aSJeff Kirsher return vp; 1087e689cf4aSJeff Kirsher } 1088e689cf4aSJeff Kirsher 1089e689cf4aSJeff Kirsher static const char *local_mac_prop = "local-mac-address"; 1090e689cf4aSJeff Kirsher 1091f73d12bdSBill Pemberton static struct vnet *vnet_find_parent(struct mdesc_handle *hp, 1092e689cf4aSJeff Kirsher u64 port_node) 1093e689cf4aSJeff Kirsher { 1094e689cf4aSJeff Kirsher const u64 *local_mac = NULL; 1095e689cf4aSJeff Kirsher u64 a; 1096e689cf4aSJeff Kirsher 1097e689cf4aSJeff Kirsher mdesc_for_each_arc(a, hp, port_node, MDESC_ARC_TYPE_BACK) { 1098e689cf4aSJeff Kirsher u64 target = mdesc_arc_target(hp, a); 1099e689cf4aSJeff Kirsher const char *name; 1100e689cf4aSJeff Kirsher 1101e689cf4aSJeff Kirsher name = mdesc_get_property(hp, target, "name", NULL); 1102e689cf4aSJeff Kirsher if (!name || strcmp(name, "network")) 1103e689cf4aSJeff Kirsher continue; 1104e689cf4aSJeff Kirsher 1105e689cf4aSJeff Kirsher local_mac = mdesc_get_property(hp, target, 1106e689cf4aSJeff Kirsher local_mac_prop, NULL); 1107e689cf4aSJeff Kirsher if (local_mac) 1108e689cf4aSJeff Kirsher break; 1109e689cf4aSJeff Kirsher } 1110e689cf4aSJeff Kirsher if (!local_mac) 1111e689cf4aSJeff Kirsher return ERR_PTR(-ENODEV); 1112e689cf4aSJeff Kirsher 1113e689cf4aSJeff Kirsher return vnet_find_or_create(local_mac); 1114e689cf4aSJeff Kirsher } 1115e689cf4aSJeff Kirsher 1116e689cf4aSJeff Kirsher static struct ldc_channel_config vnet_ldc_cfg = { 1117e689cf4aSJeff Kirsher .event = vnet_event, 1118e689cf4aSJeff Kirsher .mtu = 64, 1119e689cf4aSJeff Kirsher .mode = LDC_MODE_UNRELIABLE, 1120e689cf4aSJeff Kirsher }; 1121e689cf4aSJeff Kirsher 1122e689cf4aSJeff Kirsher static struct vio_driver_ops vnet_vio_ops = { 1123e689cf4aSJeff Kirsher .send_attr = vnet_send_attr, 1124e689cf4aSJeff Kirsher .handle_attr = vnet_handle_attr, 1125e689cf4aSJeff Kirsher .handshake_complete = vnet_handshake_complete, 1126e689cf4aSJeff Kirsher }; 1127e689cf4aSJeff Kirsher 1128f73d12bdSBill Pemberton static void print_version(void) 1129e689cf4aSJeff Kirsher { 1130e689cf4aSJeff Kirsher printk_once(KERN_INFO "%s", version); 1131e689cf4aSJeff Kirsher } 1132e689cf4aSJeff Kirsher 1133e689cf4aSJeff Kirsher const char *remote_macaddr_prop = "remote-mac-address"; 1134e689cf4aSJeff Kirsher 1135f73d12bdSBill Pemberton static int vnet_port_probe(struct vio_dev *vdev, 1136e689cf4aSJeff Kirsher const struct vio_device_id *id) 1137e689cf4aSJeff Kirsher { 1138e689cf4aSJeff Kirsher struct mdesc_handle *hp; 1139e689cf4aSJeff Kirsher struct vnet_port *port; 1140e689cf4aSJeff Kirsher unsigned long flags; 1141e689cf4aSJeff Kirsher struct vnet *vp; 1142e689cf4aSJeff Kirsher const u64 *rmac; 1143e689cf4aSJeff Kirsher int len, i, err, switch_port; 1144e689cf4aSJeff Kirsher 1145e689cf4aSJeff Kirsher print_version(); 1146e689cf4aSJeff Kirsher 1147e689cf4aSJeff Kirsher hp = mdesc_grab(); 1148e689cf4aSJeff Kirsher 1149e689cf4aSJeff Kirsher vp = vnet_find_parent(hp, vdev->mp); 1150e689cf4aSJeff Kirsher if (IS_ERR(vp)) { 1151e689cf4aSJeff Kirsher pr_err("Cannot find port parent vnet\n"); 1152e689cf4aSJeff Kirsher err = PTR_ERR(vp); 1153e689cf4aSJeff Kirsher goto err_out_put_mdesc; 1154e689cf4aSJeff Kirsher } 1155e689cf4aSJeff Kirsher 1156e689cf4aSJeff Kirsher rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len); 1157e689cf4aSJeff Kirsher err = -ENODEV; 1158e689cf4aSJeff Kirsher if (!rmac) { 1159e689cf4aSJeff Kirsher pr_err("Port lacks %s property\n", remote_macaddr_prop); 1160e689cf4aSJeff Kirsher goto err_out_put_mdesc; 1161e689cf4aSJeff Kirsher } 1162e689cf4aSJeff Kirsher 1163e689cf4aSJeff Kirsher port = kzalloc(sizeof(*port), GFP_KERNEL); 1164e689cf4aSJeff Kirsher err = -ENOMEM; 1165e404decbSJoe Perches if (!port) 1166e689cf4aSJeff Kirsher goto err_out_put_mdesc; 1167e689cf4aSJeff Kirsher 1168e689cf4aSJeff Kirsher for (i = 0; i < ETH_ALEN; i++) 1169e689cf4aSJeff Kirsher port->raddr[i] = (*rmac >> (5 - i) * 8) & 0xff; 1170e689cf4aSJeff Kirsher 1171e689cf4aSJeff Kirsher port->vp = vp; 1172e689cf4aSJeff Kirsher 1173e689cf4aSJeff Kirsher err = vio_driver_init(&port->vio, vdev, VDEV_NETWORK, 1174e689cf4aSJeff Kirsher vnet_versions, ARRAY_SIZE(vnet_versions), 1175e689cf4aSJeff Kirsher &vnet_vio_ops, vp->dev->name); 1176e689cf4aSJeff Kirsher if (err) 1177e689cf4aSJeff Kirsher goto err_out_free_port; 1178e689cf4aSJeff Kirsher 1179e689cf4aSJeff Kirsher err = vio_ldc_alloc(&port->vio, &vnet_ldc_cfg, port); 1180e689cf4aSJeff Kirsher if (err) 1181e689cf4aSJeff Kirsher goto err_out_free_port; 1182e689cf4aSJeff Kirsher 1183e689cf4aSJeff Kirsher err = vnet_port_alloc_tx_bufs(port); 1184e689cf4aSJeff Kirsher if (err) 1185e689cf4aSJeff Kirsher goto err_out_free_ldc; 1186e689cf4aSJeff Kirsher 1187e689cf4aSJeff Kirsher INIT_HLIST_NODE(&port->hash); 1188e689cf4aSJeff Kirsher INIT_LIST_HEAD(&port->list); 1189e689cf4aSJeff Kirsher 1190e689cf4aSJeff Kirsher switch_port = 0; 1191e689cf4aSJeff Kirsher if (mdesc_get_property(hp, vdev->mp, "switch-port", NULL) != NULL) 1192e689cf4aSJeff Kirsher switch_port = 1; 1193e689cf4aSJeff Kirsher port->switch_port = switch_port; 1194e689cf4aSJeff Kirsher 1195e689cf4aSJeff Kirsher spin_lock_irqsave(&vp->lock, flags); 1196e689cf4aSJeff Kirsher if (switch_port) 1197e689cf4aSJeff Kirsher list_add(&port->list, &vp->port_list); 1198e689cf4aSJeff Kirsher else 1199e689cf4aSJeff Kirsher list_add_tail(&port->list, &vp->port_list); 1200e689cf4aSJeff Kirsher hlist_add_head(&port->hash, &vp->port_hash[vnet_hashfn(port->raddr)]); 1201e689cf4aSJeff Kirsher spin_unlock_irqrestore(&vp->lock, flags); 1202e689cf4aSJeff Kirsher 1203e689cf4aSJeff Kirsher dev_set_drvdata(&vdev->dev, port); 1204e689cf4aSJeff Kirsher 1205e689cf4aSJeff Kirsher pr_info("%s: PORT ( remote-mac %pM%s )\n", 1206e689cf4aSJeff Kirsher vp->dev->name, port->raddr, switch_port ? " switch-port" : ""); 1207e689cf4aSJeff Kirsher 1208e689cf4aSJeff Kirsher vio_port_up(&port->vio); 1209e689cf4aSJeff Kirsher 1210e689cf4aSJeff Kirsher mdesc_release(hp); 1211e689cf4aSJeff Kirsher 1212e689cf4aSJeff Kirsher return 0; 1213e689cf4aSJeff Kirsher 1214e689cf4aSJeff Kirsher err_out_free_ldc: 1215e689cf4aSJeff Kirsher vio_ldc_free(&port->vio); 1216e689cf4aSJeff Kirsher 1217e689cf4aSJeff Kirsher err_out_free_port: 1218e689cf4aSJeff Kirsher kfree(port); 1219e689cf4aSJeff Kirsher 1220e689cf4aSJeff Kirsher err_out_put_mdesc: 1221e689cf4aSJeff Kirsher mdesc_release(hp); 1222e689cf4aSJeff Kirsher return err; 1223e689cf4aSJeff Kirsher } 1224e689cf4aSJeff Kirsher 1225e689cf4aSJeff Kirsher static int vnet_port_remove(struct vio_dev *vdev) 1226e689cf4aSJeff Kirsher { 1227e689cf4aSJeff Kirsher struct vnet_port *port = dev_get_drvdata(&vdev->dev); 1228e689cf4aSJeff Kirsher 1229e689cf4aSJeff Kirsher if (port) { 1230e689cf4aSJeff Kirsher struct vnet *vp = port->vp; 1231e689cf4aSJeff Kirsher unsigned long flags; 1232e689cf4aSJeff Kirsher 1233e689cf4aSJeff Kirsher del_timer_sync(&port->vio.timer); 1234e689cf4aSJeff Kirsher 1235e689cf4aSJeff Kirsher spin_lock_irqsave(&vp->lock, flags); 1236e689cf4aSJeff Kirsher list_del(&port->list); 1237e689cf4aSJeff Kirsher hlist_del(&port->hash); 1238e689cf4aSJeff Kirsher spin_unlock_irqrestore(&vp->lock, flags); 1239e689cf4aSJeff Kirsher 1240e689cf4aSJeff Kirsher vnet_port_free_tx_bufs(port); 1241e689cf4aSJeff Kirsher vio_ldc_free(&port->vio); 1242e689cf4aSJeff Kirsher 1243e689cf4aSJeff Kirsher dev_set_drvdata(&vdev->dev, NULL); 1244e689cf4aSJeff Kirsher 1245e689cf4aSJeff Kirsher kfree(port); 1246e689cf4aSJeff Kirsher } 1247e689cf4aSJeff Kirsher return 0; 1248e689cf4aSJeff Kirsher } 1249e689cf4aSJeff Kirsher 1250e689cf4aSJeff Kirsher static const struct vio_device_id vnet_port_match[] = { 1251e689cf4aSJeff Kirsher { 1252e689cf4aSJeff Kirsher .type = "vnet-port", 1253e689cf4aSJeff Kirsher }, 1254e689cf4aSJeff Kirsher {}, 1255e689cf4aSJeff Kirsher }; 1256e689cf4aSJeff Kirsher MODULE_DEVICE_TABLE(vio, vnet_port_match); 1257e689cf4aSJeff Kirsher 1258e689cf4aSJeff Kirsher static struct vio_driver vnet_port_driver = { 1259e689cf4aSJeff Kirsher .id_table = vnet_port_match, 1260e689cf4aSJeff Kirsher .probe = vnet_port_probe, 1261e689cf4aSJeff Kirsher .remove = vnet_port_remove, 1262e689cf4aSJeff Kirsher .name = "vnet_port", 1263e689cf4aSJeff Kirsher }; 1264e689cf4aSJeff Kirsher 1265e689cf4aSJeff Kirsher static int __init vnet_init(void) 1266e689cf4aSJeff Kirsher { 1267e689cf4aSJeff Kirsher return vio_register_driver(&vnet_port_driver); 1268e689cf4aSJeff Kirsher } 1269e689cf4aSJeff Kirsher 1270e689cf4aSJeff Kirsher static void __exit vnet_exit(void) 1271e689cf4aSJeff Kirsher { 1272e689cf4aSJeff Kirsher vio_unregister_driver(&vnet_port_driver); 1273e689cf4aSJeff Kirsher } 1274e689cf4aSJeff Kirsher 1275e689cf4aSJeff Kirsher module_init(vnet_init); 1276e689cf4aSJeff Kirsher module_exit(vnet_exit); 1277