14c521e422f2837b9652fa00a064a01d009f939b6David S. Miller/* sunvnet.c: Sun LDOM Virtual Network Driver. 24c521e422f2837b9652fa00a064a01d009f939b6David S. Miller * 33d452e55ef905fc6fbf813a66c16de1293e243a1David S. Miller * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net> 44c521e422f2837b9652fa00a064a01d009f939b6David S. Miller */ 54c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 64d5870ec103e6569851b9710f0093f072b08439aJoe Perches#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 74d5870ec103e6569851b9710f0093f072b08439aJoe Perches 84c521e422f2837b9652fa00a064a01d009f939b6David S. Miller#include <linux/module.h> 94c521e422f2837b9652fa00a064a01d009f939b6David S. Miller#include <linux/kernel.h> 104c521e422f2837b9652fa00a064a01d009f939b6David S. Miller#include <linux/types.h> 114c521e422f2837b9652fa00a064a01d009f939b6David S. Miller#include <linux/slab.h> 124c521e422f2837b9652fa00a064a01d009f939b6David S. Miller#include <linux/delay.h> 134c521e422f2837b9652fa00a064a01d009f939b6David S. Miller#include <linux/init.h> 144c521e422f2837b9652fa00a064a01d009f939b6David S. Miller#include <linux/netdevice.h> 154c521e422f2837b9652fa00a064a01d009f939b6David S. Miller#include <linux/ethtool.h> 164c521e422f2837b9652fa00a064a01d009f939b6David S. Miller#include <linux/etherdevice.h> 179184a046328d2dfc9f2cf0f831e649a108492124David S. Miller#include <linux/mutex.h> 184c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 194c521e422f2837b9652fa00a064a01d009f939b6David S. Miller#include <asm/vio.h> 204c521e422f2837b9652fa00a064a01d009f939b6David S. Miller#include <asm/ldc.h> 214c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 224c521e422f2837b9652fa00a064a01d009f939b6David S. Miller#include "sunvnet.h" 234c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 244c521e422f2837b9652fa00a064a01d009f939b6David S. Miller#define DRV_MODULE_NAME "sunvnet" 254c521e422f2837b9652fa00a064a01d009f939b6David S. Miller#define DRV_MODULE_VERSION "1.0" 264c521e422f2837b9652fa00a064a01d009f939b6David S. Miller#define DRV_MODULE_RELDATE "June 25, 2007" 274c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 284c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic char version[] __devinitdata = 294c521e422f2837b9652fa00a064a01d009f939b6David S. Miller DRV_MODULE_NAME ".c:v" DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n"; 304c521e422f2837b9652fa00a064a01d009f939b6David S. MillerMODULE_AUTHOR("David S. Miller (davem@davemloft.net)"); 314c521e422f2837b9652fa00a064a01d009f939b6David S. MillerMODULE_DESCRIPTION("Sun LDOM virtual network driver"); 324c521e422f2837b9652fa00a064a01d009f939b6David S. MillerMODULE_LICENSE("GPL"); 334c521e422f2837b9652fa00a064a01d009f939b6David S. MillerMODULE_VERSION(DRV_MODULE_VERSION); 344c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 354c521e422f2837b9652fa00a064a01d009f939b6David S. Miller/* Ordered from largest major to lowest */ 364c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic struct vio_version vnet_versions[] = { 374c521e422f2837b9652fa00a064a01d009f939b6David S. Miller { .major = 1, .minor = 0 }, 384c521e422f2837b9652fa00a064a01d009f939b6David S. Miller}; 394c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 404c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic inline u32 vnet_tx_dring_avail(struct vio_dring_state *dr) 414c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 424c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return vio_dring_avail(dr, VNET_TX_RING_SIZE); 434c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 444c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 454c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int vnet_handle_unknown(struct vnet_port *port, void *arg) 464c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 474c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_msg_tag *pkt = arg; 484c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 494d5870ec103e6569851b9710f0093f072b08439aJoe Perches pr_err("Received unknown msg [%02x:%02x:%04x:%08x]\n", 504c521e422f2837b9652fa00a064a01d009f939b6David S. Miller pkt->type, pkt->stype, pkt->stype_env, pkt->sid); 514d5870ec103e6569851b9710f0093f072b08439aJoe Perches pr_err("Resetting connection\n"); 524c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 534c521e422f2837b9652fa00a064a01d009f939b6David S. Miller ldc_disconnect(port->vio.lp); 544c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 554c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return -ECONNRESET; 564c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 574c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 584c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int vnet_send_attr(struct vio_driver_state *vio) 594c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 604c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vnet_port *port = to_vnet_port(vio); 614c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct net_device *dev = port->vp->dev; 624c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_net_attr_info pkt; 634c521e422f2837b9652fa00a064a01d009f939b6David S. Miller int i; 644c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 654c521e422f2837b9652fa00a064a01d009f939b6David S. Miller memset(&pkt, 0, sizeof(pkt)); 664c521e422f2837b9652fa00a064a01d009f939b6David S. Miller pkt.tag.type = VIO_TYPE_CTRL; 674c521e422f2837b9652fa00a064a01d009f939b6David S. Miller pkt.tag.stype = VIO_SUBTYPE_INFO; 684c521e422f2837b9652fa00a064a01d009f939b6David S. Miller pkt.tag.stype_env = VIO_ATTR_INFO; 694c521e422f2837b9652fa00a064a01d009f939b6David S. Miller pkt.tag.sid = vio_send_sid(vio); 704c521e422f2837b9652fa00a064a01d009f939b6David S. Miller pkt.xfer_mode = VIO_DRING_MODE; 714c521e422f2837b9652fa00a064a01d009f939b6David S. Miller pkt.addr_type = VNET_ADDR_ETHERMAC; 724c521e422f2837b9652fa00a064a01d009f939b6David S. Miller pkt.ack_freq = 0; 734c521e422f2837b9652fa00a064a01d009f939b6David S. Miller for (i = 0; i < 6; i++) 744c521e422f2837b9652fa00a064a01d009f939b6David S. Miller pkt.addr |= (u64)dev->dev_addr[i] << ((5 - i) * 8); 754c521e422f2837b9652fa00a064a01d009f939b6David S. Miller pkt.mtu = ETH_FRAME_LEN; 764c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 774c521e422f2837b9652fa00a064a01d009f939b6David S. Miller viodbg(HS, "SEND NET ATTR xmode[0x%x] atype[0x%x] addr[%llx] " 784c521e422f2837b9652fa00a064a01d009f939b6David S. Miller "ackfreq[%u] mtu[%llu]\n", 794c521e422f2837b9652fa00a064a01d009f939b6David S. Miller pkt.xfer_mode, pkt.addr_type, 804c521e422f2837b9652fa00a064a01d009f939b6David S. Miller (unsigned long long) pkt.addr, 814c521e422f2837b9652fa00a064a01d009f939b6David S. Miller pkt.ack_freq, 824c521e422f2837b9652fa00a064a01d009f939b6David S. Miller (unsigned long long) pkt.mtu); 834c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 844c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return vio_ldc_send(vio, &pkt, sizeof(pkt)); 854c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 864c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 874c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int handle_attr_info(struct vio_driver_state *vio, 884c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_net_attr_info *pkt) 894c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 904c521e422f2837b9652fa00a064a01d009f939b6David S. Miller viodbg(HS, "GOT NET ATTR INFO xmode[0x%x] atype[0x%x] addr[%llx] " 914c521e422f2837b9652fa00a064a01d009f939b6David S. Miller "ackfreq[%u] mtu[%llu]\n", 924c521e422f2837b9652fa00a064a01d009f939b6David S. Miller pkt->xfer_mode, pkt->addr_type, 934c521e422f2837b9652fa00a064a01d009f939b6David S. Miller (unsigned long long) pkt->addr, 944c521e422f2837b9652fa00a064a01d009f939b6David S. Miller pkt->ack_freq, 954c521e422f2837b9652fa00a064a01d009f939b6David S. Miller (unsigned long long) pkt->mtu); 964c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 974c521e422f2837b9652fa00a064a01d009f939b6David S. Miller pkt->tag.sid = vio_send_sid(vio); 984c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 994c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (pkt->xfer_mode != VIO_DRING_MODE || 1004c521e422f2837b9652fa00a064a01d009f939b6David S. Miller pkt->addr_type != VNET_ADDR_ETHERMAC || 1014c521e422f2837b9652fa00a064a01d009f939b6David S. Miller pkt->mtu != ETH_FRAME_LEN) { 1024c521e422f2837b9652fa00a064a01d009f939b6David S. Miller viodbg(HS, "SEND NET ATTR NACK\n"); 1034c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1044c521e422f2837b9652fa00a064a01d009f939b6David S. Miller pkt->tag.stype = VIO_SUBTYPE_NACK; 1054c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1064c521e422f2837b9652fa00a064a01d009f939b6David S. Miller (void) vio_ldc_send(vio, pkt, sizeof(*pkt)); 1074c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1084c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return -ECONNRESET; 1094c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } else { 1104c521e422f2837b9652fa00a064a01d009f939b6David S. Miller viodbg(HS, "SEND NET ATTR ACK\n"); 1114c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1124c521e422f2837b9652fa00a064a01d009f939b6David S. Miller pkt->tag.stype = VIO_SUBTYPE_ACK; 1134c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1144c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return vio_ldc_send(vio, pkt, sizeof(*pkt)); 1154c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 1164c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1174c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 1184c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1194c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int handle_attr_ack(struct vio_driver_state *vio, 1204c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_net_attr_info *pkt) 1214c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 1224c521e422f2837b9652fa00a064a01d009f939b6David S. Miller viodbg(HS, "GOT NET ATTR ACK\n"); 1234c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1244c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return 0; 1254c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 1264c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1274c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int handle_attr_nack(struct vio_driver_state *vio, 1284c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_net_attr_info *pkt) 1294c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 1304c521e422f2837b9652fa00a064a01d009f939b6David S. Miller viodbg(HS, "GOT NET ATTR NACK\n"); 1314c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1324c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return -ECONNRESET; 1334c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 1344c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1354c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int vnet_handle_attr(struct vio_driver_state *vio, void *arg) 1364c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 1374c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_net_attr_info *pkt = arg; 1384c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1394c521e422f2837b9652fa00a064a01d009f939b6David S. Miller switch (pkt->tag.stype) { 1404c521e422f2837b9652fa00a064a01d009f939b6David S. Miller case VIO_SUBTYPE_INFO: 1414c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return handle_attr_info(vio, pkt); 1424c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1434c521e422f2837b9652fa00a064a01d009f939b6David S. Miller case VIO_SUBTYPE_ACK: 1444c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return handle_attr_ack(vio, pkt); 1454c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1464c521e422f2837b9652fa00a064a01d009f939b6David S. Miller case VIO_SUBTYPE_NACK: 1474c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return handle_attr_nack(vio, pkt); 1484c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1494c521e422f2837b9652fa00a064a01d009f939b6David S. Miller default: 1504c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return -ECONNRESET; 1514c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 1524c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 1534c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1544c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic void vnet_handshake_complete(struct vio_driver_state *vio) 1554c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 1564c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_dring_state *dr; 1574c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1584c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr = &vio->drings[VIO_DRIVER_RX_RING]; 1594c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr->snd_nxt = dr->rcv_nxt = 1; 1604c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1614c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr = &vio->drings[VIO_DRIVER_TX_RING]; 1624c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr->snd_nxt = dr->rcv_nxt = 1; 1634c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 1644c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1654c521e422f2837b9652fa00a064a01d009f939b6David S. Miller/* The hypervisor interface that implements copying to/from imported 1664c521e422f2837b9652fa00a064a01d009f939b6David S. Miller * memory from another domain requires that copies are done to 8-byte 1674c521e422f2837b9652fa00a064a01d009f939b6David S. Miller * aligned buffers, and that the lengths of such copies are also 8-byte 1684c521e422f2837b9652fa00a064a01d009f939b6David S. Miller * multiples. 1694c521e422f2837b9652fa00a064a01d009f939b6David S. Miller * 1704c521e422f2837b9652fa00a064a01d009f939b6David S. Miller * So we align skb->data to an 8-byte multiple and pad-out the data 1714c521e422f2837b9652fa00a064a01d009f939b6David S. Miller * area so we can round the copy length up to the next multiple of 1724c521e422f2837b9652fa00a064a01d009f939b6David S. Miller * 8 for the copy. 1734c521e422f2837b9652fa00a064a01d009f939b6David S. Miller * 1744c521e422f2837b9652fa00a064a01d009f939b6David S. Miller * The transmitter puts the actual start of the packet 6 bytes into 1754c521e422f2837b9652fa00a064a01d009f939b6David S. Miller * the buffer it sends over, so that the IP headers after the ethernet 1764c521e422f2837b9652fa00a064a01d009f939b6David S. Miller * header are aligned properly. These 6 bytes are not in the descriptor 1774c521e422f2837b9652fa00a064a01d009f939b6David S. Miller * length, they are simply implied. This offset is represented using 1784c521e422f2837b9652fa00a064a01d009f939b6David S. Miller * the VNET_PACKET_SKIP macro. 1794c521e422f2837b9652fa00a064a01d009f939b6David S. Miller */ 1804c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic struct sk_buff *alloc_and_align_skb(struct net_device *dev, 1814c521e422f2837b9652fa00a064a01d009f939b6David S. Miller unsigned int len) 1824c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 1834c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct sk_buff *skb = netdev_alloc_skb(dev, len+VNET_PACKET_SKIP+8+8); 1844c521e422f2837b9652fa00a064a01d009f939b6David S. Miller unsigned long addr, off; 1854c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1864c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (unlikely(!skb)) 1874c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return NULL; 1884c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1894c521e422f2837b9652fa00a064a01d009f939b6David S. Miller addr = (unsigned long) skb->data; 1904c521e422f2837b9652fa00a064a01d009f939b6David S. Miller off = ((addr + 7UL) & ~7UL) - addr; 1914c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (off) 1924c521e422f2837b9652fa00a064a01d009f939b6David S. Miller skb_reserve(skb, off); 1934c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1944c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return skb; 1954c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 1964c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1974c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int vnet_rx_one(struct vnet_port *port, unsigned int len, 1984c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct ldc_trans_cookie *cookies, int ncookies) 1994c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 2004c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct net_device *dev = port->vp->dev; 2014c521e422f2837b9652fa00a064a01d009f939b6David S. Miller unsigned int copy_len; 2024c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct sk_buff *skb; 2034c521e422f2837b9652fa00a064a01d009f939b6David S. Miller int err; 2044c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 2054c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = -EMSGSIZE; 2064c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (unlikely(len < ETH_ZLEN || len > ETH_FRAME_LEN)) { 2074c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dev->stats.rx_length_errors++; 2084c521e422f2837b9652fa00a064a01d009f939b6David S. Miller goto out_dropped; 2094c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 2104c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 2114c521e422f2837b9652fa00a064a01d009f939b6David S. Miller skb = alloc_and_align_skb(dev, len); 2124c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = -ENOMEM; 2134c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (unlikely(!skb)) { 2144c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dev->stats.rx_missed_errors++; 2154c521e422f2837b9652fa00a064a01d009f939b6David S. Miller goto out_dropped; 2164c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 2174c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 2184c521e422f2837b9652fa00a064a01d009f939b6David S. Miller copy_len = (len + VNET_PACKET_SKIP + 7U) & ~7U; 2194c521e422f2837b9652fa00a064a01d009f939b6David S. Miller skb_put(skb, copy_len); 2204c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = ldc_copy(port->vio.lp, LDC_COPY_IN, 2214c521e422f2837b9652fa00a064a01d009f939b6David S. Miller skb->data, copy_len, 0, 2224c521e422f2837b9652fa00a064a01d009f939b6David S. Miller cookies, ncookies); 2234c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (unlikely(err < 0)) { 2244c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dev->stats.rx_frame_errors++; 2254c521e422f2837b9652fa00a064a01d009f939b6David S. Miller goto out_free_skb; 2264c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 2274c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 2284c521e422f2837b9652fa00a064a01d009f939b6David S. Miller skb_pull(skb, VNET_PACKET_SKIP); 2294c521e422f2837b9652fa00a064a01d009f939b6David S. Miller skb_trim(skb, len); 2304c521e422f2837b9652fa00a064a01d009f939b6David S. Miller skb->protocol = eth_type_trans(skb, dev); 2314c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 2324c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dev->stats.rx_packets++; 2334c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dev->stats.rx_bytes += len; 2344c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 2354c521e422f2837b9652fa00a064a01d009f939b6David S. Miller netif_rx(skb); 2364c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 2374c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return 0; 2384c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 2394c521e422f2837b9652fa00a064a01d009f939b6David S. Millerout_free_skb: 2404c521e422f2837b9652fa00a064a01d009f939b6David S. Miller kfree_skb(skb); 2414c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 2424c521e422f2837b9652fa00a064a01d009f939b6David S. Millerout_dropped: 2434c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dev->stats.rx_dropped++; 2444c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return err; 2454c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 2464c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 2474c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int vnet_send_ack(struct vnet_port *port, struct vio_dring_state *dr, 2484c521e422f2837b9652fa00a064a01d009f939b6David S. Miller u32 start, u32 end, u8 vio_dring_state) 2494c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 2504c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_dring_data hdr = { 2514c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .tag = { 2524c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .type = VIO_TYPE_DATA, 2534c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .stype = VIO_SUBTYPE_ACK, 2544c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .stype_env = VIO_DRING_DATA, 2554c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .sid = vio_send_sid(&port->vio), 2564c521e422f2837b9652fa00a064a01d009f939b6David S. Miller }, 2574c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .dring_ident = dr->ident, 2584c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .start_idx = start, 2594c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .end_idx = end, 2604c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .state = vio_dring_state, 2614c521e422f2837b9652fa00a064a01d009f939b6David S. Miller }; 2624c521e422f2837b9652fa00a064a01d009f939b6David S. Miller int err, delay; 2634c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 2644c521e422f2837b9652fa00a064a01d009f939b6David S. Miller hdr.seq = dr->snd_nxt; 2654c521e422f2837b9652fa00a064a01d009f939b6David S. Miller delay = 1; 2664c521e422f2837b9652fa00a064a01d009f939b6David S. Miller do { 2674c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = vio_ldc_send(&port->vio, &hdr, sizeof(hdr)); 2684c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (err > 0) { 2694c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr->snd_nxt++; 2704c521e422f2837b9652fa00a064a01d009f939b6David S. Miller break; 2714c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 2724c521e422f2837b9652fa00a064a01d009f939b6David S. Miller udelay(delay); 2734c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if ((delay <<= 1) > 128) 2744c521e422f2837b9652fa00a064a01d009f939b6David S. Miller delay = 128; 2754c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } while (err == -EAGAIN); 2764c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 2774c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return err; 2784c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 2794c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 2804c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic u32 next_idx(u32 idx, struct vio_dring_state *dr) 2814c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 2824c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (++idx == dr->num_entries) 2834c521e422f2837b9652fa00a064a01d009f939b6David S. Miller idx = 0; 2844c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return idx; 2854c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 2864c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 2874c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic u32 prev_idx(u32 idx, struct vio_dring_state *dr) 2884c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 2894c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (idx == 0) 2904c521e422f2837b9652fa00a064a01d009f939b6David S. Miller idx = dr->num_entries - 1; 2914c521e422f2837b9652fa00a064a01d009f939b6David S. Miller else 2924c521e422f2837b9652fa00a064a01d009f939b6David S. Miller idx--; 2934c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 2944c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return idx; 2954c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 2964c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 2974c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic struct vio_net_desc *get_rx_desc(struct vnet_port *port, 2984c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_dring_state *dr, 2994c521e422f2837b9652fa00a064a01d009f939b6David S. Miller u32 index) 3004c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 3014c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_net_desc *desc = port->vio.desc_buf; 3024c521e422f2837b9652fa00a064a01d009f939b6David S. Miller int err; 3034c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 3044c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = ldc_get_dring_entry(port->vio.lp, desc, dr->entry_size, 3054c521e422f2837b9652fa00a064a01d009f939b6David S. Miller (index * dr->entry_size), 3064c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr->cookies, dr->ncookies); 3074c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (err < 0) 3084c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return ERR_PTR(err); 3094c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 3104c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return desc; 3114c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 3124c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 3134c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int put_rx_desc(struct vnet_port *port, 3144c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_dring_state *dr, 3154c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_net_desc *desc, 3164c521e422f2837b9652fa00a064a01d009f939b6David S. Miller u32 index) 3174c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 3184c521e422f2837b9652fa00a064a01d009f939b6David S. Miller int err; 3194c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 3204c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = ldc_put_dring_entry(port->vio.lp, desc, dr->entry_size, 3214c521e422f2837b9652fa00a064a01d009f939b6David S. Miller (index * dr->entry_size), 3224c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr->cookies, dr->ncookies); 3234c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (err < 0) 3244c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return err; 3254c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 3264c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return 0; 3274c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 3284c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 3294c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int vnet_walk_rx_one(struct vnet_port *port, 3304c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_dring_state *dr, 3314c521e422f2837b9652fa00a064a01d009f939b6David S. Miller u32 index, int *needs_ack) 3324c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 3334c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_net_desc *desc = get_rx_desc(port, dr, index); 3344c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_driver_state *vio = &port->vio; 3354c521e422f2837b9652fa00a064a01d009f939b6David S. Miller int err; 3364c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 3374c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (IS_ERR(desc)) 3384c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return PTR_ERR(desc); 3394c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 3403f4528d6e91cffde49894f5252e6657d420d3d74Sam Ravnborg viodbg(DATA, "vio_walk_rx_one desc[%02x:%02x:%08x:%08x:%llx:%llx]\n", 3414c521e422f2837b9652fa00a064a01d009f939b6David S. Miller desc->hdr.state, desc->hdr.ack, 3424c521e422f2837b9652fa00a064a01d009f939b6David S. Miller desc->size, desc->ncookies, 3434c521e422f2837b9652fa00a064a01d009f939b6David S. Miller desc->cookies[0].cookie_addr, 3444c521e422f2837b9652fa00a064a01d009f939b6David S. Miller desc->cookies[0].cookie_size); 3454c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 3464c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (desc->hdr.state != VIO_DESC_READY) 3474c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return 1; 3484c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = vnet_rx_one(port, desc->size, desc->cookies, desc->ncookies); 3494c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (err == -ECONNRESET) 3504c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return err; 3514c521e422f2837b9652fa00a064a01d009f939b6David S. Miller desc->hdr.state = VIO_DESC_DONE; 3524c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = put_rx_desc(port, dr, desc, index); 3534c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (err < 0) 3544c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return err; 3554c521e422f2837b9652fa00a064a01d009f939b6David S. Miller *needs_ack = desc->hdr.ack; 3564c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return 0; 3574c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 3584c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 3594c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int vnet_walk_rx(struct vnet_port *port, struct vio_dring_state *dr, 3604c521e422f2837b9652fa00a064a01d009f939b6David S. Miller u32 start, u32 end) 3614c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 3624c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_driver_state *vio = &port->vio; 3634c521e422f2837b9652fa00a064a01d009f939b6David S. Miller int ack_start = -1, ack_end = -1; 3644c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 3654c521e422f2837b9652fa00a064a01d009f939b6David S. Miller end = (end == (u32) -1) ? prev_idx(start, dr) : next_idx(end, dr); 3664c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 3674c521e422f2837b9652fa00a064a01d009f939b6David S. Miller viodbg(DATA, "vnet_walk_rx start[%08x] end[%08x]\n", start, end); 3684c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 3694c521e422f2837b9652fa00a064a01d009f939b6David S. Miller while (start != end) { 3704c521e422f2837b9652fa00a064a01d009f939b6David S. Miller int ack = 0, err = vnet_walk_rx_one(port, dr, start, &ack); 3714c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (err == -ECONNRESET) 3724c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return err; 3734c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (err != 0) 3744c521e422f2837b9652fa00a064a01d009f939b6David S. Miller break; 3754c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (ack_start == -1) 3764c521e422f2837b9652fa00a064a01d009f939b6David S. Miller ack_start = start; 3774c521e422f2837b9652fa00a064a01d009f939b6David S. Miller ack_end = start; 3784c521e422f2837b9652fa00a064a01d009f939b6David S. Miller start = next_idx(start, dr); 3794c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (ack && start != end) { 3804c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = vnet_send_ack(port, dr, ack_start, ack_end, 3814c521e422f2837b9652fa00a064a01d009f939b6David S. Miller VIO_DRING_ACTIVE); 3824c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (err == -ECONNRESET) 3834c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return err; 3844c521e422f2837b9652fa00a064a01d009f939b6David S. Miller ack_start = -1; 3854c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 3864c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 3874c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (unlikely(ack_start == -1)) 3884c521e422f2837b9652fa00a064a01d009f939b6David S. Miller ack_start = ack_end = prev_idx(start, dr); 3894c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return vnet_send_ack(port, dr, ack_start, ack_end, VIO_DRING_STOPPED); 3904c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 3914c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 3924c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int vnet_rx(struct vnet_port *port, void *msgbuf) 3934c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 3944c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_dring_data *pkt = msgbuf; 3954c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_RX_RING]; 3964c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_driver_state *vio = &port->vio; 3974c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 3983f4528d6e91cffde49894f5252e6657d420d3d74Sam Ravnborg viodbg(DATA, "vnet_rx stype_env[%04x] seq[%016llx] rcv_nxt[%016llx]\n", 3994c521e422f2837b9652fa00a064a01d009f939b6David S. Miller pkt->tag.stype_env, pkt->seq, dr->rcv_nxt); 4004c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 4014c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (unlikely(pkt->tag.stype_env != VIO_DRING_DATA)) 4024c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return 0; 4034c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (unlikely(pkt->seq != dr->rcv_nxt)) { 4044d5870ec103e6569851b9710f0093f072b08439aJoe Perches pr_err("RX out of sequence seq[0x%llx] rcv_nxt[0x%llx]\n", 4054d5870ec103e6569851b9710f0093f072b08439aJoe Perches pkt->seq, dr->rcv_nxt); 4064c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return 0; 4074c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 4084c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 4094c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr->rcv_nxt++; 4104c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 4114c521e422f2837b9652fa00a064a01d009f939b6David S. Miller /* XXX Validate pkt->start_idx and pkt->end_idx XXX */ 4124c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 4134c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return vnet_walk_rx(port, dr, pkt->start_idx, pkt->end_idx); 4144c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 4154c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 4164c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int idx_is_pending(struct vio_dring_state *dr, u32 end) 4174c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 4184c521e422f2837b9652fa00a064a01d009f939b6David S. Miller u32 idx = dr->cons; 4194c521e422f2837b9652fa00a064a01d009f939b6David S. Miller int found = 0; 4204c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 4214c521e422f2837b9652fa00a064a01d009f939b6David S. Miller while (idx != dr->prod) { 4224c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (idx == end) { 4234c521e422f2837b9652fa00a064a01d009f939b6David S. Miller found = 1; 4244c521e422f2837b9652fa00a064a01d009f939b6David S. Miller break; 4254c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 4264c521e422f2837b9652fa00a064a01d009f939b6David S. Miller idx = next_idx(idx, dr); 4274c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 4284c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return found; 4294c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 4304c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 4314c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int vnet_ack(struct vnet_port *port, void *msgbuf) 4324c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 4334c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING]; 4344c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_dring_data *pkt = msgbuf; 4354c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct net_device *dev; 4364c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vnet *vp; 4374c521e422f2837b9652fa00a064a01d009f939b6David S. Miller u32 end; 4384c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 4394c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (unlikely(pkt->tag.stype_env != VIO_DRING_DATA)) 4404c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return 0; 4414c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 4424c521e422f2837b9652fa00a064a01d009f939b6David S. Miller end = pkt->end_idx; 4434c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (unlikely(!idx_is_pending(dr, end))) 4444c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return 0; 4454c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 4464c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr->cons = next_idx(end, dr); 4474c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 4484c521e422f2837b9652fa00a064a01d009f939b6David S. Miller vp = port->vp; 4494c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dev = vp->dev; 4504c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (unlikely(netif_queue_stopped(dev) && 4514c521e422f2837b9652fa00a064a01d009f939b6David S. Miller vnet_tx_dring_avail(dr) >= VNET_TX_WAKEUP_THRESH(dr))) 4524c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return 1; 4534c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 4544c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return 0; 4554c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 4564c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 4574c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int vnet_nack(struct vnet_port *port, void *msgbuf) 4584c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 4594c521e422f2837b9652fa00a064a01d009f939b6David S. Miller /* XXX just reset or similar XXX */ 4604c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return 0; 4614c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 4624c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 463028ebff26915df18ab0cda664e2f0582650af155David S. Millerstatic int handle_mcast(struct vnet_port *port, void *msgbuf) 464028ebff26915df18ab0cda664e2f0582650af155David S. Miller{ 465028ebff26915df18ab0cda664e2f0582650af155David S. Miller struct vio_net_mcast_info *pkt = msgbuf; 466028ebff26915df18ab0cda664e2f0582650af155David S. Miller 467028ebff26915df18ab0cda664e2f0582650af155David S. Miller if (pkt->tag.stype != VIO_SUBTYPE_ACK) 4684d5870ec103e6569851b9710f0093f072b08439aJoe Perches pr_err("%s: Got unexpected MCAST reply [%02x:%02x:%04x:%08x]\n", 469028ebff26915df18ab0cda664e2f0582650af155David S. Miller port->vp->dev->name, 470028ebff26915df18ab0cda664e2f0582650af155David S. Miller pkt->tag.type, 471028ebff26915df18ab0cda664e2f0582650af155David S. Miller pkt->tag.stype, 472028ebff26915df18ab0cda664e2f0582650af155David S. Miller pkt->tag.stype_env, 473028ebff26915df18ab0cda664e2f0582650af155David S. Miller pkt->tag.sid); 474028ebff26915df18ab0cda664e2f0582650af155David S. Miller 475028ebff26915df18ab0cda664e2f0582650af155David S. Miller return 0; 476028ebff26915df18ab0cda664e2f0582650af155David S. Miller} 477028ebff26915df18ab0cda664e2f0582650af155David S. Miller 4784c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic void maybe_tx_wakeup(struct vnet *vp) 4794c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 4804c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct net_device *dev = vp->dev; 4814c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 4824c521e422f2837b9652fa00a064a01d009f939b6David S. Miller netif_tx_lock(dev); 4834c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (likely(netif_queue_stopped(dev))) { 4844c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vnet_port *port; 4854c521e422f2837b9652fa00a064a01d009f939b6David S. Miller int wake = 1; 4864c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 4874c521e422f2837b9652fa00a064a01d009f939b6David S. Miller list_for_each_entry(port, &vp->port_list, list) { 4884c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_dring_state *dr; 4894c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 4904c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr = &port->vio.drings[VIO_DRIVER_TX_RING]; 4914c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (vnet_tx_dring_avail(dr) < 4924c521e422f2837b9652fa00a064a01d009f939b6David S. Miller VNET_TX_WAKEUP_THRESH(dr)) { 4934c521e422f2837b9652fa00a064a01d009f939b6David S. Miller wake = 0; 4944c521e422f2837b9652fa00a064a01d009f939b6David S. Miller break; 4954c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 4964c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 4974c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (wake) 4984c521e422f2837b9652fa00a064a01d009f939b6David S. Miller netif_wake_queue(dev); 4994c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 5004c521e422f2837b9652fa00a064a01d009f939b6David S. Miller netif_tx_unlock(dev); 5014c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 5024c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 5034c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic void vnet_event(void *arg, int event) 5044c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 5054c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vnet_port *port = arg; 5064c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_driver_state *vio = &port->vio; 5074c521e422f2837b9652fa00a064a01d009f939b6David S. Miller unsigned long flags; 5084c521e422f2837b9652fa00a064a01d009f939b6David S. Miller int tx_wakeup, err; 5094c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 5104c521e422f2837b9652fa00a064a01d009f939b6David S. Miller spin_lock_irqsave(&vio->lock, flags); 5114c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 5124c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (unlikely(event == LDC_EVENT_RESET || 5134c521e422f2837b9652fa00a064a01d009f939b6David S. Miller event == LDC_EVENT_UP)) { 5144c521e422f2837b9652fa00a064a01d009f939b6David S. Miller vio_link_state_change(vio, event); 5154c521e422f2837b9652fa00a064a01d009f939b6David S. Miller spin_unlock_irqrestore(&vio->lock, flags); 5164c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 517d762acdbd3b2bd9a714ace47d7b0c76133d7b295David S. Miller if (event == LDC_EVENT_RESET) 518d762acdbd3b2bd9a714ace47d7b0c76133d7b295David S. Miller vio_port_up(vio); 5194c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return; 5204c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 5214c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 5224c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (unlikely(event != LDC_EVENT_DATA_READY)) { 5234d5870ec103e6569851b9710f0093f072b08439aJoe Perches pr_warning("Unexpected LDC event %d\n", event); 5244c521e422f2837b9652fa00a064a01d009f939b6David S. Miller spin_unlock_irqrestore(&vio->lock, flags); 5254c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return; 5264c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 5274c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 5284c521e422f2837b9652fa00a064a01d009f939b6David S. Miller tx_wakeup = err = 0; 5294c521e422f2837b9652fa00a064a01d009f939b6David S. Miller while (1) { 5304c521e422f2837b9652fa00a064a01d009f939b6David S. Miller union { 5314c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_msg_tag tag; 5324c521e422f2837b9652fa00a064a01d009f939b6David S. Miller u64 raw[8]; 5334c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } msgbuf; 5344c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 5354c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = ldc_read(vio->lp, &msgbuf, sizeof(msgbuf)); 5364c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (unlikely(err < 0)) { 5374c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (err == -ECONNRESET) 5384c521e422f2837b9652fa00a064a01d009f939b6David S. Miller vio_conn_reset(vio); 5394c521e422f2837b9652fa00a064a01d009f939b6David S. Miller break; 5404c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 5414c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (err == 0) 5424c521e422f2837b9652fa00a064a01d009f939b6David S. Miller break; 5434c521e422f2837b9652fa00a064a01d009f939b6David S. Miller viodbg(DATA, "TAG [%02x:%02x:%04x:%08x]\n", 5444c521e422f2837b9652fa00a064a01d009f939b6David S. Miller msgbuf.tag.type, 5454c521e422f2837b9652fa00a064a01d009f939b6David S. Miller msgbuf.tag.stype, 5464c521e422f2837b9652fa00a064a01d009f939b6David S. Miller msgbuf.tag.stype_env, 5474c521e422f2837b9652fa00a064a01d009f939b6David S. Miller msgbuf.tag.sid); 5484c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = vio_validate_sid(vio, &msgbuf.tag); 5494c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (err < 0) 5504c521e422f2837b9652fa00a064a01d009f939b6David S. Miller break; 5514c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 5524c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (likely(msgbuf.tag.type == VIO_TYPE_DATA)) { 5534c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (msgbuf.tag.stype == VIO_SUBTYPE_INFO) { 5544c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = vnet_rx(port, &msgbuf); 5554c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } else if (msgbuf.tag.stype == VIO_SUBTYPE_ACK) { 5564c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = vnet_ack(port, &msgbuf); 5574c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (err > 0) 5584c521e422f2837b9652fa00a064a01d009f939b6David S. Miller tx_wakeup |= err; 5594c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } else if (msgbuf.tag.stype == VIO_SUBTYPE_NACK) { 5604c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = vnet_nack(port, &msgbuf); 5614c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 5624c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } else if (msgbuf.tag.type == VIO_TYPE_CTRL) { 563028ebff26915df18ab0cda664e2f0582650af155David S. Miller if (msgbuf.tag.stype_env == VNET_MCAST_INFO) 564028ebff26915df18ab0cda664e2f0582650af155David S. Miller err = handle_mcast(port, &msgbuf); 565028ebff26915df18ab0cda664e2f0582650af155David S. Miller else 566028ebff26915df18ab0cda664e2f0582650af155David S. Miller err = vio_control_pkt_engine(vio, &msgbuf); 5674c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (err) 5684c521e422f2837b9652fa00a064a01d009f939b6David S. Miller break; 5694c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } else { 5704c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = vnet_handle_unknown(port, &msgbuf); 5714c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 5724c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (err == -ECONNRESET) 5734c521e422f2837b9652fa00a064a01d009f939b6David S. Miller break; 5744c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 5754c521e422f2837b9652fa00a064a01d009f939b6David S. Miller spin_unlock(&vio->lock); 5764c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (unlikely(tx_wakeup && err != -ECONNRESET)) 5774c521e422f2837b9652fa00a064a01d009f939b6David S. Miller maybe_tx_wakeup(port->vp); 5784c521e422f2837b9652fa00a064a01d009f939b6David S. Miller local_irq_restore(flags); 5794c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 5804c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 5814c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int __vnet_tx_trigger(struct vnet_port *port) 5824c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 5834c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_dring_state *dr = &port->vio.drings[VIO_DRIVER_TX_RING]; 5844c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_dring_data hdr = { 5854c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .tag = { 5864c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .type = VIO_TYPE_DATA, 5874c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .stype = VIO_SUBTYPE_INFO, 5884c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .stype_env = VIO_DRING_DATA, 5894c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .sid = vio_send_sid(&port->vio), 5904c521e422f2837b9652fa00a064a01d009f939b6David S. Miller }, 5914c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .dring_ident = dr->ident, 5924c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .start_idx = dr->prod, 5934c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .end_idx = (u32) -1, 5944c521e422f2837b9652fa00a064a01d009f939b6David S. Miller }; 5954c521e422f2837b9652fa00a064a01d009f939b6David S. Miller int err, delay; 5964c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 5974c521e422f2837b9652fa00a064a01d009f939b6David S. Miller hdr.seq = dr->snd_nxt; 5984c521e422f2837b9652fa00a064a01d009f939b6David S. Miller delay = 1; 5994c521e422f2837b9652fa00a064a01d009f939b6David S. Miller do { 6004c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = vio_ldc_send(&port->vio, &hdr, sizeof(hdr)); 6014c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (err > 0) { 6024c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr->snd_nxt++; 6034c521e422f2837b9652fa00a064a01d009f939b6David S. Miller break; 6044c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 6054c521e422f2837b9652fa00a064a01d009f939b6David S. Miller udelay(delay); 6064c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if ((delay <<= 1) > 128) 6074c521e422f2837b9652fa00a064a01d009f939b6David S. Miller delay = 128; 6084c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } while (err == -EAGAIN); 6094c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 6104c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return err; 6114c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 6124c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 6134c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstruct vnet_port *__tx_port_find(struct vnet *vp, struct sk_buff *skb) 6144c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 6154c521e422f2837b9652fa00a064a01d009f939b6David S. Miller unsigned int hash = vnet_hashfn(skb->data); 6164c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct hlist_head *hp = &vp->port_hash[hash]; 6174c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct hlist_node *n; 6184c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vnet_port *port; 6194c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 6204c521e422f2837b9652fa00a064a01d009f939b6David S. Miller hlist_for_each_entry(port, n, hp, hash) { 6214c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (!compare_ether_addr(port->raddr, skb->data)) 6224c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return port; 6234c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 6244c521e422f2837b9652fa00a064a01d009f939b6David S. Miller port = NULL; 6254c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (!list_empty(&vp->port_list)) 6264c521e422f2837b9652fa00a064a01d009f939b6David S. Miller port = list_entry(vp->port_list.next, struct vnet_port, list); 6274c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 6284c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return port; 6294c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 6304c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 6314c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstruct vnet_port *tx_port_find(struct vnet *vp, struct sk_buff *skb) 6324c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 6334c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vnet_port *ret; 6344c521e422f2837b9652fa00a064a01d009f939b6David S. Miller unsigned long flags; 6354c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 6364c521e422f2837b9652fa00a064a01d009f939b6David S. Miller spin_lock_irqsave(&vp->lock, flags); 6374c521e422f2837b9652fa00a064a01d009f939b6David S. Miller ret = __tx_port_find(vp, skb); 6384c521e422f2837b9652fa00a064a01d009f939b6David S. Miller spin_unlock_irqrestore(&vp->lock, flags); 6394c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 6404c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return ret; 6414c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 6424c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 6434c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev) 6444c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 6454c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vnet *vp = netdev_priv(dev); 6464c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vnet_port *port = tx_port_find(vp, skb); 6474c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_dring_state *dr; 6484c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_net_desc *d; 6494c521e422f2837b9652fa00a064a01d009f939b6David S. Miller unsigned long flags; 6504c521e422f2837b9652fa00a064a01d009f939b6David S. Miller unsigned int len; 6514c521e422f2837b9652fa00a064a01d009f939b6David S. Miller void *tx_buf; 6524c521e422f2837b9652fa00a064a01d009f939b6David S. Miller int i, err; 6534c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 6544c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (unlikely(!port)) 6554c521e422f2837b9652fa00a064a01d009f939b6David S. Miller goto out_dropped; 6564c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 6574c521e422f2837b9652fa00a064a01d009f939b6David S. Miller spin_lock_irqsave(&port->vio.lock, flags); 6584c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 6594c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr = &port->vio.drings[VIO_DRIVER_TX_RING]; 6604c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (unlikely(vnet_tx_dring_avail(dr) < 2)) { 6614c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (!netif_queue_stopped(dev)) { 6624c521e422f2837b9652fa00a064a01d009f939b6David S. Miller netif_stop_queue(dev); 6634c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 6644c521e422f2837b9652fa00a064a01d009f939b6David S. Miller /* This is a hard error, log it. */ 6654d5870ec103e6569851b9710f0093f072b08439aJoe Perches netdev_err(dev, "BUG! Tx Ring full when queue awake!\n"); 6664c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dev->stats.tx_errors++; 6674c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 6684c521e422f2837b9652fa00a064a01d009f939b6David S. Miller spin_unlock_irqrestore(&port->vio.lock, flags); 6694c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return NETDEV_TX_BUSY; 6704c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 6714c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 6724c521e422f2837b9652fa00a064a01d009f939b6David S. Miller d = vio_dring_cur(dr); 6734c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 6744c521e422f2837b9652fa00a064a01d009f939b6David S. Miller tx_buf = port->tx_bufs[dr->prod].buf; 6754c521e422f2837b9652fa00a064a01d009f939b6David S. Miller skb_copy_from_linear_data(skb, tx_buf + VNET_PACKET_SKIP, skb->len); 6764c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 6774c521e422f2837b9652fa00a064a01d009f939b6David S. Miller len = skb->len; 6784c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (len < ETH_ZLEN) { 6794c521e422f2837b9652fa00a064a01d009f939b6David S. Miller len = ETH_ZLEN; 6804c521e422f2837b9652fa00a064a01d009f939b6David S. Miller memset(tx_buf+VNET_PACKET_SKIP+skb->len, 0, len - skb->len); 6814c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 6824c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 6834c521e422f2837b9652fa00a064a01d009f939b6David S. Miller d->hdr.ack = VIO_ACK_ENABLE; 6844c521e422f2837b9652fa00a064a01d009f939b6David S. Miller d->size = len; 6854c521e422f2837b9652fa00a064a01d009f939b6David S. Miller d->ncookies = port->tx_bufs[dr->prod].ncookies; 6864c521e422f2837b9652fa00a064a01d009f939b6David S. Miller for (i = 0; i < d->ncookies; i++) 6874c521e422f2837b9652fa00a064a01d009f939b6David S. Miller d->cookies[i] = port->tx_bufs[dr->prod].cookies[i]; 6884c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 6894c521e422f2837b9652fa00a064a01d009f939b6David S. Miller /* This has to be a non-SMP write barrier because we are writing 6904c521e422f2837b9652fa00a064a01d009f939b6David S. Miller * to memory which is shared with the peer LDOM. 6914c521e422f2837b9652fa00a064a01d009f939b6David S. Miller */ 6924c521e422f2837b9652fa00a064a01d009f939b6David S. Miller wmb(); 6934c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 6944c521e422f2837b9652fa00a064a01d009f939b6David S. Miller d->hdr.state = VIO_DESC_READY; 6954c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 6964c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = __vnet_tx_trigger(port); 6974c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (unlikely(err < 0)) { 6984d5870ec103e6569851b9710f0093f072b08439aJoe Perches netdev_info(dev, "TX trigger error %d\n", err); 6994c521e422f2837b9652fa00a064a01d009f939b6David S. Miller d->hdr.state = VIO_DESC_FREE; 7004c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dev->stats.tx_carrier_errors++; 7014c521e422f2837b9652fa00a064a01d009f939b6David S. Miller goto out_dropped_unlock; 7024c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 7034c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 7044c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dev->stats.tx_packets++; 7054c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dev->stats.tx_bytes += skb->len; 7064c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 7074c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr->prod = (dr->prod + 1) & (VNET_TX_RING_SIZE - 1); 7084c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (unlikely(vnet_tx_dring_avail(dr) < 2)) { 7094c521e422f2837b9652fa00a064a01d009f939b6David S. Miller netif_stop_queue(dev); 7104c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (vnet_tx_dring_avail(dr) > VNET_TX_WAKEUP_THRESH(dr)) 7114c521e422f2837b9652fa00a064a01d009f939b6David S. Miller netif_wake_queue(dev); 7124c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 7134c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 7144c521e422f2837b9652fa00a064a01d009f939b6David S. Miller spin_unlock_irqrestore(&port->vio.lock, flags); 7154c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 7164c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dev_kfree_skb(skb); 7174c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 7184c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return NETDEV_TX_OK; 7194c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 7204c521e422f2837b9652fa00a064a01d009f939b6David S. Millerout_dropped_unlock: 7214c521e422f2837b9652fa00a064a01d009f939b6David S. Miller spin_unlock_irqrestore(&port->vio.lock, flags); 7224c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 7234c521e422f2837b9652fa00a064a01d009f939b6David S. Millerout_dropped: 7244c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dev_kfree_skb(skb); 7254c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dev->stats.tx_dropped++; 7264c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return NETDEV_TX_OK; 7274c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 7284c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 7294c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic void vnet_tx_timeout(struct net_device *dev) 7304c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 7314c521e422f2837b9652fa00a064a01d009f939b6David S. Miller /* XXX Implement me XXX */ 7324c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 7334c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 7344c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int vnet_open(struct net_device *dev) 7354c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 7364c521e422f2837b9652fa00a064a01d009f939b6David S. Miller netif_carrier_on(dev); 7374c521e422f2837b9652fa00a064a01d009f939b6David S. Miller netif_start_queue(dev); 7384c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 7394c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return 0; 7404c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 7414c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 7424c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int vnet_close(struct net_device *dev) 7434c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 7444c521e422f2837b9652fa00a064a01d009f939b6David S. Miller netif_stop_queue(dev); 7454c521e422f2837b9652fa00a064a01d009f939b6David S. Miller netif_carrier_off(dev); 7464c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 7474c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return 0; 7484c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 7494c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 750028ebff26915df18ab0cda664e2f0582650af155David S. Millerstatic struct vnet_mcast_entry *__vnet_mc_find(struct vnet *vp, u8 *addr) 751028ebff26915df18ab0cda664e2f0582650af155David S. Miller{ 752028ebff26915df18ab0cda664e2f0582650af155David S. Miller struct vnet_mcast_entry *m; 753028ebff26915df18ab0cda664e2f0582650af155David S. Miller 754028ebff26915df18ab0cda664e2f0582650af155David S. Miller for (m = vp->mcast_list; m; m = m->next) { 755028ebff26915df18ab0cda664e2f0582650af155David S. Miller if (!memcmp(m->addr, addr, ETH_ALEN)) 756028ebff26915df18ab0cda664e2f0582650af155David S. Miller return m; 757028ebff26915df18ab0cda664e2f0582650af155David S. Miller } 758028ebff26915df18ab0cda664e2f0582650af155David S. Miller return NULL; 759028ebff26915df18ab0cda664e2f0582650af155David S. Miller} 760028ebff26915df18ab0cda664e2f0582650af155David S. Miller 761028ebff26915df18ab0cda664e2f0582650af155David S. Millerstatic void __update_mc_list(struct vnet *vp, struct net_device *dev) 762028ebff26915df18ab0cda664e2f0582650af155David S. Miller{ 76322bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko struct netdev_hw_addr *ha; 764028ebff26915df18ab0cda664e2f0582650af155David S. Miller 76522bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko netdev_for_each_mc_addr(ha, dev) { 766028ebff26915df18ab0cda664e2f0582650af155David S. Miller struct vnet_mcast_entry *m; 767028ebff26915df18ab0cda664e2f0582650af155David S. Miller 76822bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko m = __vnet_mc_find(vp, ha->addr); 769028ebff26915df18ab0cda664e2f0582650af155David S. Miller if (m) { 770028ebff26915df18ab0cda664e2f0582650af155David S. Miller m->hit = 1; 771028ebff26915df18ab0cda664e2f0582650af155David S. Miller continue; 772028ebff26915df18ab0cda664e2f0582650af155David S. Miller } 773028ebff26915df18ab0cda664e2f0582650af155David S. Miller 774028ebff26915df18ab0cda664e2f0582650af155David S. Miller if (!m) { 775028ebff26915df18ab0cda664e2f0582650af155David S. Miller m = kzalloc(sizeof(*m), GFP_ATOMIC); 776028ebff26915df18ab0cda664e2f0582650af155David S. Miller if (!m) 777028ebff26915df18ab0cda664e2f0582650af155David S. Miller continue; 77822bedad3ce112d5ca1eaf043d4990fa2ed698c87Jiri Pirko memcpy(m->addr, ha->addr, ETH_ALEN); 779028ebff26915df18ab0cda664e2f0582650af155David S. Miller m->hit = 1; 780028ebff26915df18ab0cda664e2f0582650af155David S. Miller 781028ebff26915df18ab0cda664e2f0582650af155David S. Miller m->next = vp->mcast_list; 782028ebff26915df18ab0cda664e2f0582650af155David S. Miller vp->mcast_list = m; 783028ebff26915df18ab0cda664e2f0582650af155David S. Miller } 784028ebff26915df18ab0cda664e2f0582650af155David S. Miller } 785028ebff26915df18ab0cda664e2f0582650af155David S. Miller} 786028ebff26915df18ab0cda664e2f0582650af155David S. Miller 787028ebff26915df18ab0cda664e2f0582650af155David S. Millerstatic void __send_mc_list(struct vnet *vp, struct vnet_port *port) 788028ebff26915df18ab0cda664e2f0582650af155David S. Miller{ 789028ebff26915df18ab0cda664e2f0582650af155David S. Miller struct vio_net_mcast_info info; 790028ebff26915df18ab0cda664e2f0582650af155David S. Miller struct vnet_mcast_entry *m, **pp; 791028ebff26915df18ab0cda664e2f0582650af155David S. Miller int n_addrs; 792028ebff26915df18ab0cda664e2f0582650af155David S. Miller 793028ebff26915df18ab0cda664e2f0582650af155David S. Miller memset(&info, 0, sizeof(info)); 794028ebff26915df18ab0cda664e2f0582650af155David S. Miller 795028ebff26915df18ab0cda664e2f0582650af155David S. Miller info.tag.type = VIO_TYPE_CTRL; 796028ebff26915df18ab0cda664e2f0582650af155David S. Miller info.tag.stype = VIO_SUBTYPE_INFO; 797028ebff26915df18ab0cda664e2f0582650af155David S. Miller info.tag.stype_env = VNET_MCAST_INFO; 798028ebff26915df18ab0cda664e2f0582650af155David S. Miller info.tag.sid = vio_send_sid(&port->vio); 799028ebff26915df18ab0cda664e2f0582650af155David S. Miller info.set = 1; 800028ebff26915df18ab0cda664e2f0582650af155David S. Miller 801028ebff26915df18ab0cda664e2f0582650af155David S. Miller n_addrs = 0; 802028ebff26915df18ab0cda664e2f0582650af155David S. Miller for (m = vp->mcast_list; m; m = m->next) { 803028ebff26915df18ab0cda664e2f0582650af155David S. Miller if (m->sent) 804028ebff26915df18ab0cda664e2f0582650af155David S. Miller continue; 805028ebff26915df18ab0cda664e2f0582650af155David S. Miller m->sent = 1; 806028ebff26915df18ab0cda664e2f0582650af155David S. Miller memcpy(&info.mcast_addr[n_addrs * ETH_ALEN], 807028ebff26915df18ab0cda664e2f0582650af155David S. Miller m->addr, ETH_ALEN); 808028ebff26915df18ab0cda664e2f0582650af155David S. Miller if (++n_addrs == VNET_NUM_MCAST) { 809028ebff26915df18ab0cda664e2f0582650af155David S. Miller info.count = n_addrs; 810028ebff26915df18ab0cda664e2f0582650af155David S. Miller 811028ebff26915df18ab0cda664e2f0582650af155David S. Miller (void) vio_ldc_send(&port->vio, &info, 812028ebff26915df18ab0cda664e2f0582650af155David S. Miller sizeof(info)); 813028ebff26915df18ab0cda664e2f0582650af155David S. Miller n_addrs = 0; 814028ebff26915df18ab0cda664e2f0582650af155David S. Miller } 815028ebff26915df18ab0cda664e2f0582650af155David S. Miller } 816028ebff26915df18ab0cda664e2f0582650af155David S. Miller if (n_addrs) { 817028ebff26915df18ab0cda664e2f0582650af155David S. Miller info.count = n_addrs; 818028ebff26915df18ab0cda664e2f0582650af155David S. Miller (void) vio_ldc_send(&port->vio, &info, sizeof(info)); 819028ebff26915df18ab0cda664e2f0582650af155David S. Miller } 820028ebff26915df18ab0cda664e2f0582650af155David S. Miller 821028ebff26915df18ab0cda664e2f0582650af155David S. Miller info.set = 0; 822028ebff26915df18ab0cda664e2f0582650af155David S. Miller 823028ebff26915df18ab0cda664e2f0582650af155David S. Miller n_addrs = 0; 824028ebff26915df18ab0cda664e2f0582650af155David S. Miller pp = &vp->mcast_list; 825028ebff26915df18ab0cda664e2f0582650af155David S. Miller while ((m = *pp) != NULL) { 826028ebff26915df18ab0cda664e2f0582650af155David S. Miller if (m->hit) { 827028ebff26915df18ab0cda664e2f0582650af155David S. Miller m->hit = 0; 828028ebff26915df18ab0cda664e2f0582650af155David S. Miller pp = &m->next; 829028ebff26915df18ab0cda664e2f0582650af155David S. Miller continue; 830028ebff26915df18ab0cda664e2f0582650af155David S. Miller } 831028ebff26915df18ab0cda664e2f0582650af155David S. Miller 832028ebff26915df18ab0cda664e2f0582650af155David S. Miller memcpy(&info.mcast_addr[n_addrs * ETH_ALEN], 833028ebff26915df18ab0cda664e2f0582650af155David S. Miller m->addr, ETH_ALEN); 834028ebff26915df18ab0cda664e2f0582650af155David S. Miller if (++n_addrs == VNET_NUM_MCAST) { 835028ebff26915df18ab0cda664e2f0582650af155David S. Miller info.count = n_addrs; 836028ebff26915df18ab0cda664e2f0582650af155David S. Miller (void) vio_ldc_send(&port->vio, &info, 837028ebff26915df18ab0cda664e2f0582650af155David S. Miller sizeof(info)); 838028ebff26915df18ab0cda664e2f0582650af155David S. Miller n_addrs = 0; 839028ebff26915df18ab0cda664e2f0582650af155David S. Miller } 840028ebff26915df18ab0cda664e2f0582650af155David S. Miller 841028ebff26915df18ab0cda664e2f0582650af155David S. Miller *pp = m->next; 842028ebff26915df18ab0cda664e2f0582650af155David S. Miller kfree(m); 843028ebff26915df18ab0cda664e2f0582650af155David S. Miller } 844028ebff26915df18ab0cda664e2f0582650af155David S. Miller if (n_addrs) { 845028ebff26915df18ab0cda664e2f0582650af155David S. Miller info.count = n_addrs; 846028ebff26915df18ab0cda664e2f0582650af155David S. Miller (void) vio_ldc_send(&port->vio, &info, sizeof(info)); 847028ebff26915df18ab0cda664e2f0582650af155David S. Miller } 848028ebff26915df18ab0cda664e2f0582650af155David S. Miller} 849028ebff26915df18ab0cda664e2f0582650af155David S. Miller 8504c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic void vnet_set_rx_mode(struct net_device *dev) 8514c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 852028ebff26915df18ab0cda664e2f0582650af155David S. Miller struct vnet *vp = netdev_priv(dev); 853028ebff26915df18ab0cda664e2f0582650af155David S. Miller struct vnet_port *port; 854028ebff26915df18ab0cda664e2f0582650af155David S. Miller unsigned long flags; 855028ebff26915df18ab0cda664e2f0582650af155David S. Miller 856028ebff26915df18ab0cda664e2f0582650af155David S. Miller spin_lock_irqsave(&vp->lock, flags); 857028ebff26915df18ab0cda664e2f0582650af155David S. Miller if (!list_empty(&vp->port_list)) { 858028ebff26915df18ab0cda664e2f0582650af155David S. Miller port = list_entry(vp->port_list.next, struct vnet_port, list); 859028ebff26915df18ab0cda664e2f0582650af155David S. Miller 860028ebff26915df18ab0cda664e2f0582650af155David S. Miller if (port->switch_port) { 861028ebff26915df18ab0cda664e2f0582650af155David S. Miller __update_mc_list(vp, dev); 862028ebff26915df18ab0cda664e2f0582650af155David S. Miller __send_mc_list(vp, port); 863028ebff26915df18ab0cda664e2f0582650af155David S. Miller } 864028ebff26915df18ab0cda664e2f0582650af155David S. Miller } 865028ebff26915df18ab0cda664e2f0582650af155David S. Miller spin_unlock_irqrestore(&vp->lock, flags); 8664c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 8674c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 8684c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int vnet_change_mtu(struct net_device *dev, int new_mtu) 8694c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 8704c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (new_mtu != ETH_DATA_LEN) 8714c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return -EINVAL; 8724c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 8734c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dev->mtu = new_mtu; 8744c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return 0; 8754c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 8764c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 8774c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int vnet_set_mac_addr(struct net_device *dev, void *p) 8784c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 8794c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return -EINVAL; 8804c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 8814c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 8824c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic void vnet_get_drvinfo(struct net_device *dev, 8834c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct ethtool_drvinfo *info) 8844c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 8854c521e422f2837b9652fa00a064a01d009f939b6David S. Miller strcpy(info->driver, DRV_MODULE_NAME); 8864c521e422f2837b9652fa00a064a01d009f939b6David S. Miller strcpy(info->version, DRV_MODULE_VERSION); 8874c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 8884c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 8894c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic u32 vnet_get_msglevel(struct net_device *dev) 8904c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 8914c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vnet *vp = netdev_priv(dev); 8924c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return vp->msg_enable; 8934c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 8944c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 8954c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic void vnet_set_msglevel(struct net_device *dev, u32 value) 8964c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 8974c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vnet *vp = netdev_priv(dev); 8984c521e422f2837b9652fa00a064a01d009f939b6David S. Miller vp->msg_enable = value; 8994c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 9004c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 9014c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic const struct ethtool_ops vnet_ethtool_ops = { 9024c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .get_drvinfo = vnet_get_drvinfo, 9034c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .get_msglevel = vnet_get_msglevel, 9044c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .set_msglevel = vnet_set_msglevel, 9054c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .get_link = ethtool_op_get_link, 9064c521e422f2837b9652fa00a064a01d009f939b6David S. Miller}; 9074c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 9084c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic void vnet_port_free_tx_bufs(struct vnet_port *port) 9094c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 9104c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_dring_state *dr; 9114c521e422f2837b9652fa00a064a01d009f939b6David S. Miller int i; 9124c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 9134c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr = &port->vio.drings[VIO_DRIVER_TX_RING]; 9144c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (dr->base) { 9154c521e422f2837b9652fa00a064a01d009f939b6David S. Miller ldc_free_exp_dring(port->vio.lp, dr->base, 9164c521e422f2837b9652fa00a064a01d009f939b6David S. Miller (dr->entry_size * dr->num_entries), 9174c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr->cookies, dr->ncookies); 9184c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr->base = NULL; 9194c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr->entry_size = 0; 9204c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr->num_entries = 0; 9214c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr->pending = 0; 9224c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr->ncookies = 0; 9234c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 9244c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 9254c521e422f2837b9652fa00a064a01d009f939b6David S. Miller for (i = 0; i < VNET_TX_RING_SIZE; i++) { 9264c521e422f2837b9652fa00a064a01d009f939b6David S. Miller void *buf = port->tx_bufs[i].buf; 9274c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 9284c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (!buf) 9294c521e422f2837b9652fa00a064a01d009f939b6David S. Miller continue; 9304c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 9314c521e422f2837b9652fa00a064a01d009f939b6David S. Miller ldc_unmap(port->vio.lp, 9324c521e422f2837b9652fa00a064a01d009f939b6David S. Miller port->tx_bufs[i].cookies, 9334c521e422f2837b9652fa00a064a01d009f939b6David S. Miller port->tx_bufs[i].ncookies); 9344c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 9354c521e422f2837b9652fa00a064a01d009f939b6David S. Miller kfree(buf); 9364c521e422f2837b9652fa00a064a01d009f939b6David S. Miller port->tx_bufs[i].buf = NULL; 9374c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 9384c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 9394c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 9404c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int __devinit vnet_port_alloc_tx_bufs(struct vnet_port *port) 9414c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 9424c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vio_dring_state *dr; 9434c521e422f2837b9652fa00a064a01d009f939b6David S. Miller unsigned long len; 9444c521e422f2837b9652fa00a064a01d009f939b6David S. Miller int i, err, ncookies; 9454c521e422f2837b9652fa00a064a01d009f939b6David S. Miller void *dring; 9464c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 9474c521e422f2837b9652fa00a064a01d009f939b6David S. Miller for (i = 0; i < VNET_TX_RING_SIZE; i++) { 9484c521e422f2837b9652fa00a064a01d009f939b6David S. Miller void *buf = kzalloc(ETH_FRAME_LEN + 8, GFP_KERNEL); 9494c521e422f2837b9652fa00a064a01d009f939b6David S. Miller int map_len = (ETH_FRAME_LEN + 7) & ~7; 9504c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 9514c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = -ENOMEM; 952e404decb0fb017be80552adee894b35307b6c7b4Joe Perches if (!buf) 9534c521e422f2837b9652fa00a064a01d009f939b6David S. Miller goto err_out; 954e404decb0fb017be80552adee894b35307b6c7b4Joe Perches 9554c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = -EFAULT; 9564c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if ((unsigned long)buf & (8UL - 1)) { 9574d5870ec103e6569851b9710f0093f072b08439aJoe Perches pr_err("TX buffer misaligned\n"); 9584c521e422f2837b9652fa00a064a01d009f939b6David S. Miller kfree(buf); 9594c521e422f2837b9652fa00a064a01d009f939b6David S. Miller goto err_out; 9604c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 9614c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 9624c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = ldc_map_single(port->vio.lp, buf, map_len, 9634c521e422f2837b9652fa00a064a01d009f939b6David S. Miller port->tx_bufs[i].cookies, 2, 9644c521e422f2837b9652fa00a064a01d009f939b6David S. Miller (LDC_MAP_SHADOW | 9654c521e422f2837b9652fa00a064a01d009f939b6David S. Miller LDC_MAP_DIRECT | 9664c521e422f2837b9652fa00a064a01d009f939b6David S. Miller LDC_MAP_RW)); 9674c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (err < 0) { 9684c521e422f2837b9652fa00a064a01d009f939b6David S. Miller kfree(buf); 9694c521e422f2837b9652fa00a064a01d009f939b6David S. Miller goto err_out; 9704c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 9714c521e422f2837b9652fa00a064a01d009f939b6David S. Miller port->tx_bufs[i].buf = buf; 9724c521e422f2837b9652fa00a064a01d009f939b6David S. Miller port->tx_bufs[i].ncookies = err; 9734c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 9744c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 9754c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr = &port->vio.drings[VIO_DRIVER_TX_RING]; 9764c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 9774c521e422f2837b9652fa00a064a01d009f939b6David S. Miller len = (VNET_TX_RING_SIZE * 9784c521e422f2837b9652fa00a064a01d009f939b6David S. Miller (sizeof(struct vio_net_desc) + 9794c521e422f2837b9652fa00a064a01d009f939b6David S. Miller (sizeof(struct ldc_trans_cookie) * 2))); 9804c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 9814c521e422f2837b9652fa00a064a01d009f939b6David S. Miller ncookies = VIO_MAX_RING_COOKIES; 9824c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dring = ldc_alloc_exp_dring(port->vio.lp, len, 9834c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr->cookies, &ncookies, 9844c521e422f2837b9652fa00a064a01d009f939b6David S. Miller (LDC_MAP_SHADOW | 9854c521e422f2837b9652fa00a064a01d009f939b6David S. Miller LDC_MAP_DIRECT | 9864c521e422f2837b9652fa00a064a01d009f939b6David S. Miller LDC_MAP_RW)); 9874c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (IS_ERR(dring)) { 9884c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = PTR_ERR(dring); 9894c521e422f2837b9652fa00a064a01d009f939b6David S. Miller goto err_out; 9904c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 9914c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 9924c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr->base = dring; 9934c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr->entry_size = (sizeof(struct vio_net_desc) + 9944c521e422f2837b9652fa00a064a01d009f939b6David S. Miller (sizeof(struct ldc_trans_cookie) * 2)); 9954c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr->num_entries = VNET_TX_RING_SIZE; 9964c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr->prod = dr->cons = 0; 9974c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr->pending = VNET_TX_RING_SIZE; 9984c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dr->ncookies = ncookies; 9994c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 10004c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return 0; 10014c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 10024c521e422f2837b9652fa00a064a01d009f939b6David S. Millererr_out: 10034c521e422f2837b9652fa00a064a01d009f939b6David S. Miller vnet_port_free_tx_bufs(port); 10044c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 10054c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return err; 10064c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 10074c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 10089184a046328d2dfc9f2cf0f831e649a108492124David S. Millerstatic LIST_HEAD(vnet_list); 10099184a046328d2dfc9f2cf0f831e649a108492124David S. Millerstatic DEFINE_MUTEX(vnet_list_mutex); 10109184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 10118fd17f2e6c973efdb2e3fcb5026d204441dd01fdDavid S. Millerstatic const struct net_device_ops vnet_ops = { 10128fd17f2e6c973efdb2e3fcb5026d204441dd01fdDavid S. Miller .ndo_open = vnet_open, 10138fd17f2e6c973efdb2e3fcb5026d204441dd01fdDavid S. Miller .ndo_stop = vnet_close, 1014afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko .ndo_set_rx_mode = vnet_set_rx_mode, 10158fd17f2e6c973efdb2e3fcb5026d204441dd01fdDavid S. Miller .ndo_set_mac_address = vnet_set_mac_addr, 1016240c102d9c54fee7fdc87a4ef2fabc7eb539e00aBen Hutchings .ndo_validate_addr = eth_validate_addr, 10178fd17f2e6c973efdb2e3fcb5026d204441dd01fdDavid S. Miller .ndo_tx_timeout = vnet_tx_timeout, 10188fd17f2e6c973efdb2e3fcb5026d204441dd01fdDavid S. Miller .ndo_change_mtu = vnet_change_mtu, 10198fd17f2e6c973efdb2e3fcb5026d204441dd01fdDavid S. Miller .ndo_start_xmit = vnet_start_xmit, 10208fd17f2e6c973efdb2e3fcb5026d204441dd01fdDavid S. Miller}; 10218fd17f2e6c973efdb2e3fcb5026d204441dd01fdDavid S. Miller 10229184a046328d2dfc9f2cf0f831e649a108492124David S. Millerstatic struct vnet * __devinit vnet_new(const u64 *local_mac) 10239184a046328d2dfc9f2cf0f831e649a108492124David S. Miller{ 10249184a046328d2dfc9f2cf0f831e649a108492124David S. Miller struct net_device *dev; 10259184a046328d2dfc9f2cf0f831e649a108492124David S. Miller struct vnet *vp; 10269184a046328d2dfc9f2cf0f831e649a108492124David S. Miller int err, i; 10279184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 10289184a046328d2dfc9f2cf0f831e649a108492124David S. Miller dev = alloc_etherdev(sizeof(*vp)); 102941de8d4cff21a2e81e3d9ff66f5f7c903f9c3ab1Joe Perches if (!dev) 10309184a046328d2dfc9f2cf0f831e649a108492124David S. Miller return ERR_PTR(-ENOMEM); 10319184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 10329184a046328d2dfc9f2cf0f831e649a108492124David S. Miller for (i = 0; i < ETH_ALEN; i++) 10339184a046328d2dfc9f2cf0f831e649a108492124David S. Miller dev->dev_addr[i] = (*local_mac >> (5 - i) * 8) & 0xff; 10349184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 10359184a046328d2dfc9f2cf0f831e649a108492124David S. Miller memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); 10369184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 10379184a046328d2dfc9f2cf0f831e649a108492124David S. Miller vp = netdev_priv(dev); 10389184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 10399184a046328d2dfc9f2cf0f831e649a108492124David S. Miller spin_lock_init(&vp->lock); 10409184a046328d2dfc9f2cf0f831e649a108492124David S. Miller vp->dev = dev; 10419184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 10429184a046328d2dfc9f2cf0f831e649a108492124David S. Miller INIT_LIST_HEAD(&vp->port_list); 10439184a046328d2dfc9f2cf0f831e649a108492124David S. Miller for (i = 0; i < VNET_PORT_HASH_SIZE; i++) 10449184a046328d2dfc9f2cf0f831e649a108492124David S. Miller INIT_HLIST_HEAD(&vp->port_hash[i]); 10459184a046328d2dfc9f2cf0f831e649a108492124David S. Miller INIT_LIST_HEAD(&vp->list); 10469184a046328d2dfc9f2cf0f831e649a108492124David S. Miller vp->local_mac = *local_mac; 10479184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 10488fd17f2e6c973efdb2e3fcb5026d204441dd01fdDavid S. Miller dev->netdev_ops = &vnet_ops; 10499184a046328d2dfc9f2cf0f831e649a108492124David S. Miller dev->ethtool_ops = &vnet_ethtool_ops; 10509184a046328d2dfc9f2cf0f831e649a108492124David S. Miller dev->watchdog_timeo = VNET_TX_TIMEOUT; 10519184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 10529184a046328d2dfc9f2cf0f831e649a108492124David S. Miller err = register_netdev(dev); 10539184a046328d2dfc9f2cf0f831e649a108492124David S. Miller if (err) { 10544d5870ec103e6569851b9710f0093f072b08439aJoe Perches pr_err("Cannot register net device, aborting\n"); 10559184a046328d2dfc9f2cf0f831e649a108492124David S. Miller goto err_out_free_dev; 10569184a046328d2dfc9f2cf0f831e649a108492124David S. Miller } 10579184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 10584d5870ec103e6569851b9710f0093f072b08439aJoe Perches netdev_info(dev, "Sun LDOM vnet %pM\n", dev->dev_addr); 10599184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 10609184a046328d2dfc9f2cf0f831e649a108492124David S. Miller list_add(&vp->list, &vnet_list); 10619184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 10629184a046328d2dfc9f2cf0f831e649a108492124David S. Miller return vp; 10639184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 10649184a046328d2dfc9f2cf0f831e649a108492124David S. Millererr_out_free_dev: 10659184a046328d2dfc9f2cf0f831e649a108492124David S. Miller free_netdev(dev); 10669184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 10679184a046328d2dfc9f2cf0f831e649a108492124David S. Miller return ERR_PTR(err); 10689184a046328d2dfc9f2cf0f831e649a108492124David S. Miller} 10699184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 10709184a046328d2dfc9f2cf0f831e649a108492124David S. Millerstatic struct vnet * __devinit vnet_find_or_create(const u64 *local_mac) 10719184a046328d2dfc9f2cf0f831e649a108492124David S. Miller{ 10729184a046328d2dfc9f2cf0f831e649a108492124David S. Miller struct vnet *iter, *vp; 10739184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 10749184a046328d2dfc9f2cf0f831e649a108492124David S. Miller mutex_lock(&vnet_list_mutex); 10759184a046328d2dfc9f2cf0f831e649a108492124David S. Miller vp = NULL; 10769184a046328d2dfc9f2cf0f831e649a108492124David S. Miller list_for_each_entry(iter, &vnet_list, list) { 10779184a046328d2dfc9f2cf0f831e649a108492124David S. Miller if (iter->local_mac == *local_mac) { 10789184a046328d2dfc9f2cf0f831e649a108492124David S. Miller vp = iter; 10799184a046328d2dfc9f2cf0f831e649a108492124David S. Miller break; 10809184a046328d2dfc9f2cf0f831e649a108492124David S. Miller } 10819184a046328d2dfc9f2cf0f831e649a108492124David S. Miller } 10829184a046328d2dfc9f2cf0f831e649a108492124David S. Miller if (!vp) 10839184a046328d2dfc9f2cf0f831e649a108492124David S. Miller vp = vnet_new(local_mac); 10849184a046328d2dfc9f2cf0f831e649a108492124David S. Miller mutex_unlock(&vnet_list_mutex); 10859184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 10869184a046328d2dfc9f2cf0f831e649a108492124David S. Miller return vp; 10879184a046328d2dfc9f2cf0f831e649a108492124David S. Miller} 10889184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 10899184a046328d2dfc9f2cf0f831e649a108492124David S. Millerstatic const char *local_mac_prop = "local-mac-address"; 10909184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 10919184a046328d2dfc9f2cf0f831e649a108492124David S. Millerstatic struct vnet * __devinit vnet_find_parent(struct mdesc_handle *hp, 10929184a046328d2dfc9f2cf0f831e649a108492124David S. Miller u64 port_node) 10939184a046328d2dfc9f2cf0f831e649a108492124David S. Miller{ 10949184a046328d2dfc9f2cf0f831e649a108492124David S. Miller const u64 *local_mac = NULL; 10959184a046328d2dfc9f2cf0f831e649a108492124David S. Miller u64 a; 10969184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 10979184a046328d2dfc9f2cf0f831e649a108492124David S. Miller mdesc_for_each_arc(a, hp, port_node, MDESC_ARC_TYPE_BACK) { 10989184a046328d2dfc9f2cf0f831e649a108492124David S. Miller u64 target = mdesc_arc_target(hp, a); 10999184a046328d2dfc9f2cf0f831e649a108492124David S. Miller const char *name; 11009184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 11019184a046328d2dfc9f2cf0f831e649a108492124David S. Miller name = mdesc_get_property(hp, target, "name", NULL); 11029184a046328d2dfc9f2cf0f831e649a108492124David S. Miller if (!name || strcmp(name, "network")) 11039184a046328d2dfc9f2cf0f831e649a108492124David S. Miller continue; 11049184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 11059184a046328d2dfc9f2cf0f831e649a108492124David S. Miller local_mac = mdesc_get_property(hp, target, 11069184a046328d2dfc9f2cf0f831e649a108492124David S. Miller local_mac_prop, NULL); 11079184a046328d2dfc9f2cf0f831e649a108492124David S. Miller if (local_mac) 11089184a046328d2dfc9f2cf0f831e649a108492124David S. Miller break; 11099184a046328d2dfc9f2cf0f831e649a108492124David S. Miller } 11109184a046328d2dfc9f2cf0f831e649a108492124David S. Miller if (!local_mac) 11119184a046328d2dfc9f2cf0f831e649a108492124David S. Miller return ERR_PTR(-ENODEV); 11129184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 11139184a046328d2dfc9f2cf0f831e649a108492124David S. Miller return vnet_find_or_create(local_mac); 11149184a046328d2dfc9f2cf0f831e649a108492124David S. Miller} 11159184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 11164c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic struct ldc_channel_config vnet_ldc_cfg = { 11174c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .event = vnet_event, 11184c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .mtu = 64, 11194c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .mode = LDC_MODE_UNRELIABLE, 11204c521e422f2837b9652fa00a064a01d009f939b6David S. Miller}; 11214c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 11224c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic struct vio_driver_ops vnet_vio_ops = { 11234c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .send_attr = vnet_send_attr, 11244c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .handle_attr = vnet_handle_attr, 11254c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .handshake_complete = vnet_handshake_complete, 11264c521e422f2837b9652fa00a064a01d009f939b6David S. Miller}; 11274c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 1128aa782d3195c8a1f6da9a44f1862f098f41bfe8a2Adrian Bunkstatic void __devinit print_version(void) 11299184a046328d2dfc9f2cf0f831e649a108492124David S. Miller{ 11304d5870ec103e6569851b9710f0093f072b08439aJoe Perches printk_once(KERN_INFO "%s", version); 11319184a046328d2dfc9f2cf0f831e649a108492124David S. Miller} 11329184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 11334c521e422f2837b9652fa00a064a01d009f939b6David S. Millerconst char *remote_macaddr_prop = "remote-mac-address"; 11344c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 11354c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int __devinit vnet_port_probe(struct vio_dev *vdev, 11364c521e422f2837b9652fa00a064a01d009f939b6David S. Miller const struct vio_device_id *id) 11374c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 113843fdf27470b216ebdef47e09ff83bed2f2894b13David S. Miller struct mdesc_handle *hp; 11394c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vnet_port *port; 11404c521e422f2837b9652fa00a064a01d009f939b6David S. Miller unsigned long flags; 11414c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vnet *vp; 11424c521e422f2837b9652fa00a064a01d009f939b6David S. Miller const u64 *rmac; 11434c521e422f2837b9652fa00a064a01d009f939b6David S. Miller int len, i, err, switch_port; 11444c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 11459184a046328d2dfc9f2cf0f831e649a108492124David S. Miller print_version(); 11464c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 114743fdf27470b216ebdef47e09ff83bed2f2894b13David S. Miller hp = mdesc_grab(); 114843fdf27470b216ebdef47e09ff83bed2f2894b13David S. Miller 11499184a046328d2dfc9f2cf0f831e649a108492124David S. Miller vp = vnet_find_parent(hp, vdev->mp); 11509184a046328d2dfc9f2cf0f831e649a108492124David S. Miller if (IS_ERR(vp)) { 11514d5870ec103e6569851b9710f0093f072b08439aJoe Perches pr_err("Cannot find port parent vnet\n"); 11529184a046328d2dfc9f2cf0f831e649a108492124David S. Miller err = PTR_ERR(vp); 11539184a046328d2dfc9f2cf0f831e649a108492124David S. Miller goto err_out_put_mdesc; 11549184a046328d2dfc9f2cf0f831e649a108492124David S. Miller } 11559184a046328d2dfc9f2cf0f831e649a108492124David S. Miller 115643fdf27470b216ebdef47e09ff83bed2f2894b13David S. Miller rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len); 115743fdf27470b216ebdef47e09ff83bed2f2894b13David S. Miller err = -ENODEV; 11584c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (!rmac) { 11594d5870ec103e6569851b9710f0093f072b08439aJoe Perches pr_err("Port lacks %s property\n", remote_macaddr_prop); 116043fdf27470b216ebdef47e09ff83bed2f2894b13David S. Miller goto err_out_put_mdesc; 11614c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 11624c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 11634c521e422f2837b9652fa00a064a01d009f939b6David S. Miller port = kzalloc(sizeof(*port), GFP_KERNEL); 116443fdf27470b216ebdef47e09ff83bed2f2894b13David S. Miller err = -ENOMEM; 1165e404decb0fb017be80552adee894b35307b6c7b4Joe Perches if (!port) 116643fdf27470b216ebdef47e09ff83bed2f2894b13David S. Miller goto err_out_put_mdesc; 11674c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 11684c521e422f2837b9652fa00a064a01d009f939b6David S. Miller for (i = 0; i < ETH_ALEN; i++) 11694c521e422f2837b9652fa00a064a01d009f939b6David S. Miller port->raddr[i] = (*rmac >> (5 - i) * 8) & 0xff; 11704c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 11714c521e422f2837b9652fa00a064a01d009f939b6David S. Miller port->vp = vp; 11724c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 117343fdf27470b216ebdef47e09ff83bed2f2894b13David S. Miller err = vio_driver_init(&port->vio, vdev, VDEV_NETWORK, 11744c521e422f2837b9652fa00a064a01d009f939b6David S. Miller vnet_versions, ARRAY_SIZE(vnet_versions), 11754c521e422f2837b9652fa00a064a01d009f939b6David S. Miller &vnet_vio_ops, vp->dev->name); 11764c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (err) 11774c521e422f2837b9652fa00a064a01d009f939b6David S. Miller goto err_out_free_port; 11784c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 11794c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = vio_ldc_alloc(&port->vio, &vnet_ldc_cfg, port); 11804c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (err) 11814c521e422f2837b9652fa00a064a01d009f939b6David S. Miller goto err_out_free_port; 11824c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 11834c521e422f2837b9652fa00a064a01d009f939b6David S. Miller err = vnet_port_alloc_tx_bufs(port); 11844c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (err) 11854c521e422f2837b9652fa00a064a01d009f939b6David S. Miller goto err_out_free_ldc; 11864c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 11874c521e422f2837b9652fa00a064a01d009f939b6David S. Miller INIT_HLIST_NODE(&port->hash); 11884c521e422f2837b9652fa00a064a01d009f939b6David S. Miller INIT_LIST_HEAD(&port->list); 11894c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 11904c521e422f2837b9652fa00a064a01d009f939b6David S. Miller switch_port = 0; 119143fdf27470b216ebdef47e09ff83bed2f2894b13David S. Miller if (mdesc_get_property(hp, vdev->mp, "switch-port", NULL) != NULL) 11924c521e422f2837b9652fa00a064a01d009f939b6David S. Miller switch_port = 1; 1193028ebff26915df18ab0cda664e2f0582650af155David S. Miller port->switch_port = switch_port; 11944c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 11954c521e422f2837b9652fa00a064a01d009f939b6David S. Miller spin_lock_irqsave(&vp->lock, flags); 11964c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (switch_port) 11974c521e422f2837b9652fa00a064a01d009f939b6David S. Miller list_add(&port->list, &vp->port_list); 11984c521e422f2837b9652fa00a064a01d009f939b6David S. Miller else 11994c521e422f2837b9652fa00a064a01d009f939b6David S. Miller list_add_tail(&port->list, &vp->port_list); 12004c521e422f2837b9652fa00a064a01d009f939b6David S. Miller hlist_add_head(&port->hash, &vp->port_hash[vnet_hashfn(port->raddr)]); 12014c521e422f2837b9652fa00a064a01d009f939b6David S. Miller spin_unlock_irqrestore(&vp->lock, flags); 12024c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 12034c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dev_set_drvdata(&vdev->dev, port); 12044c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 12054d5870ec103e6569851b9710f0093f072b08439aJoe Perches pr_info("%s: PORT ( remote-mac %pM%s )\n", 12064d5870ec103e6569851b9710f0093f072b08439aJoe Perches vp->dev->name, port->raddr, switch_port ? " switch-port" : ""); 12074c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 12084c521e422f2837b9652fa00a064a01d009f939b6David S. Miller vio_port_up(&port->vio); 12094c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 121043fdf27470b216ebdef47e09ff83bed2f2894b13David S. Miller mdesc_release(hp); 121143fdf27470b216ebdef47e09ff83bed2f2894b13David S. Miller 12124c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return 0; 12134c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 12144c521e422f2837b9652fa00a064a01d009f939b6David S. Millererr_out_free_ldc: 12154c521e422f2837b9652fa00a064a01d009f939b6David S. Miller vio_ldc_free(&port->vio); 12164c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 12174c521e422f2837b9652fa00a064a01d009f939b6David S. Millererr_out_free_port: 12184c521e422f2837b9652fa00a064a01d009f939b6David S. Miller kfree(port); 12194c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 122043fdf27470b216ebdef47e09ff83bed2f2894b13David S. Millererr_out_put_mdesc: 122143fdf27470b216ebdef47e09ff83bed2f2894b13David S. Miller mdesc_release(hp); 12224c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return err; 12234c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 12244c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 12254c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int vnet_port_remove(struct vio_dev *vdev) 12264c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 12274c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vnet_port *port = dev_get_drvdata(&vdev->dev); 12284c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 12294c521e422f2837b9652fa00a064a01d009f939b6David S. Miller if (port) { 12304c521e422f2837b9652fa00a064a01d009f939b6David S. Miller struct vnet *vp = port->vp; 12314c521e422f2837b9652fa00a064a01d009f939b6David S. Miller unsigned long flags; 12324c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 12334c521e422f2837b9652fa00a064a01d009f939b6David S. Miller del_timer_sync(&port->vio.timer); 12344c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 12354c521e422f2837b9652fa00a064a01d009f939b6David S. Miller spin_lock_irqsave(&vp->lock, flags); 12364c521e422f2837b9652fa00a064a01d009f939b6David S. Miller list_del(&port->list); 12374c521e422f2837b9652fa00a064a01d009f939b6David S. Miller hlist_del(&port->hash); 12384c521e422f2837b9652fa00a064a01d009f939b6David S. Miller spin_unlock_irqrestore(&vp->lock, flags); 12394c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 12404c521e422f2837b9652fa00a064a01d009f939b6David S. Miller vnet_port_free_tx_bufs(port); 12414c521e422f2837b9652fa00a064a01d009f939b6David S. Miller vio_ldc_free(&port->vio); 12424c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 12434c521e422f2837b9652fa00a064a01d009f939b6David S. Miller dev_set_drvdata(&vdev->dev, NULL); 12444c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 12454c521e422f2837b9652fa00a064a01d009f939b6David S. Miller kfree(port); 12464c521e422f2837b9652fa00a064a01d009f939b6David S. Miller } 12474c521e422f2837b9652fa00a064a01d009f939b6David S. Miller return 0; 12484c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 12494c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 12503d452e55ef905fc6fbf813a66c16de1293e243a1David S. Millerstatic const struct vio_device_id vnet_port_match[] = { 12514c521e422f2837b9652fa00a064a01d009f939b6David S. Miller { 12524c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .type = "vnet-port", 12534c521e422f2837b9652fa00a064a01d009f939b6David S. Miller }, 12544c521e422f2837b9652fa00a064a01d009f939b6David S. Miller {}, 12554c521e422f2837b9652fa00a064a01d009f939b6David S. Miller}; 1256da68e0814a83649f7063c33562f535b60396b566Fabio Massimo Di NittoMODULE_DEVICE_TABLE(vio, vnet_port_match); 12574c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 12584c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic struct vio_driver vnet_port_driver = { 12594c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .id_table = vnet_port_match, 12604c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .probe = vnet_port_probe, 12614c521e422f2837b9652fa00a064a01d009f939b6David S. Miller .remove = vnet_port_remove, 1262cb52d8970eee65bf2c47d9a91bd4f58b17f595f4Benjamin Herrenschmidt .name = "vnet_port", 12634c521e422f2837b9652fa00a064a01d009f939b6David S. Miller}; 12644c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 12654c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic int __init vnet_init(void) 12664c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 12679184a046328d2dfc9f2cf0f831e649a108492124David S. Miller return vio_register_driver(&vnet_port_driver); 12684c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 12694c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 12704c521e422f2837b9652fa00a064a01d009f939b6David S. Millerstatic void __exit vnet_exit(void) 12714c521e422f2837b9652fa00a064a01d009f939b6David S. Miller{ 12724c521e422f2837b9652fa00a064a01d009f939b6David S. Miller vio_unregister_driver(&vnet_port_driver); 12734c521e422f2837b9652fa00a064a01d009f939b6David S. Miller} 12744c521e422f2837b9652fa00a064a01d009f939b6David S. Miller 12754c521e422f2837b9652fa00a064a01d009f939b6David S. Millermodule_init(vnet_init); 12764c521e422f2837b9652fa00a064a01d009f939b6David S. Millermodule_exit(vnet_exit); 1277