netdev: bfin_mac: add support for wake-on-lan magic packets
[safe/jmp/linux-2.6] / drivers / net / iseries_veth.c
index 57ba1a1..ba1de59 100644 (file)
@@ -56,9 +56,7 @@
  * number of packets outstanding to a remote partition at a time.
  */
 
-#include <linux/config.h>
 #include <linux/module.h>
-#include <linux/version.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
 #include <linux/ethtool.h>
+#include <linux/if_ether.h>
+#include <linux/slab.h>
 
 #include <asm/abs_addr.h>
-#include <asm/iSeries/mf.h>
+#include <asm/iseries/mf.h>
 #include <asm/uaccess.h>
-
+#include <asm/firmware.h>
 #include <asm/iseries/hv_lp_config.h>
-#include <asm/iSeries/HvTypes.h>
+#include <asm/iseries/hv_types.h>
 #include <asm/iseries/hv_lp_event.h>
 #include <asm/iommu.h>
 #include <asm/vio.h>
@@ -167,7 +167,7 @@ struct veth_msg {
 
 struct veth_lpar_connection {
        HvLpIndex remote_lp;
-       struct work_struct statemachine_wq;
+       struct delayed_work statemachine_wq;
        struct veth_msg *msgs;
        int num_events;
        struct veth_cap_data local_caps;
@@ -197,7 +197,6 @@ struct veth_lpar_connection {
 
 struct veth_port {
        struct device *dev;
-       struct net_device_stats stats;
        u64 mac_addr;
        HvLpIndexMap lpar_map;
 
@@ -310,7 +309,8 @@ static void veth_complete_allocation(void *parm, int number)
 
 static int veth_allocate_events(HvLpIndex rlp, int number)
 {
-       struct veth_allocation vc = { COMPLETION_INITIALIZER(vc.c), 0 };
+       struct veth_allocation vc =
+               { COMPLETION_INITIALIZER_ONSTACK(vc.c), 0 };
 
        mf_allocate_lp_events(rlp, HvLpEvent_Type_VirtualLan,
                            sizeof(struct veth_lpevent), number,
@@ -385,7 +385,7 @@ static struct attribute *veth_cnx_default_attrs[] = {
        NULL
 };
 
-static struct sysfs_ops veth_cnx_sysfs_ops = {
+static const struct sysfs_ops veth_cnx_sysfs_ops = {
                .show = veth_cnx_attribute_show
 };
 
@@ -430,7 +430,7 @@ SIMPLE_PORT_ATTR(promiscuous);
 SIMPLE_PORT_ATTR(num_mcast);
 CUSTOM_PORT_ATTR(lpar_map, "0x%X\n", port->lpar_map);
 CUSTOM_PORT_ATTR(stopped_map, "0x%X\n", port->stopped_map);
-CUSTOM_PORT_ATTR(mac_addr, "0x%lX\n", port->mac_addr);
+CUSTOM_PORT_ATTR(mac_addr, "0x%llX\n", port->mac_addr);
 
 #define GET_PORT_ATTR(_name)   (&veth_port_attr_##_name.attr)
 static struct attribute *veth_port_default_attrs[] = {
@@ -442,7 +442,7 @@ static struct attribute *veth_port_default_attrs[] = {
        NULL
 };
 
-static struct sysfs_ops veth_port_sysfs_ops = {
+static const struct sysfs_ops veth_port_sysfs_ops = {
        .show = veth_port_attribute_show
 };
 
@@ -457,7 +457,7 @@ static struct kobj_type veth_port_ktype = {
 
 static inline void veth_kick_statemachine(struct veth_lpar_connection *cnx)
 {
-       schedule_work(&cnx->statemachine_wq);
+       schedule_delayed_work(&cnx->statemachine_wq, 0);
 }
 
 static void veth_take_cap(struct veth_lpar_connection *cnx,
@@ -496,7 +496,7 @@ static void veth_take_cap_ack(struct veth_lpar_connection *cnx,
                           cnx->remote_lp);
        } else {
                memcpy(&cnx->cap_ack_event, event,
-                      sizeof(&cnx->cap_ack_event));
+                      sizeof(cnx->cap_ack_event));
                cnx->state |= VETH_STATE_GOTCAPACK;
                veth_kick_statemachine(cnx);
        }
@@ -587,13 +587,13 @@ static void veth_handle_int(struct veth_lpevent *event)
        };
 }
 
-static void veth_handle_event(struct HvLpEvent *event, struct pt_regs *regs)
+static void veth_handle_event(struct HvLpEvent *event)
 {
        struct veth_lpevent *veth_event = (struct veth_lpevent *)event;
 
-       if (event->xFlags.xFunction == HvLpEvent_Function_Ack)
+       if (hvlpevent_is_ack(event))
                veth_handle_ack(veth_event);
-       else if (event->xFlags.xFunction == HvLpEvent_Function_Int)
+       else
                veth_handle_int(veth_event);
 }
 
@@ -605,10 +605,10 @@ static int veth_process_caps(struct veth_lpar_connection *cnx)
        /* Convert timer to jiffies */
        cnx->ack_timeout = remote_caps->ack_timeout * HZ / 1000000;
 
-       if ( (remote_caps->num_buffers == 0)
-            || (remote_caps->ack_threshold > VETH_MAX_ACKS_PER_MSG)
-            || (remote_caps->ack_threshold == 0)
-            || (cnx->ack_timeout == 0) ) {
+       if ( (remote_caps->num_buffers == 0) ||
+            (remote_caps->ack_threshold > VETH_MAX_ACKS_PER_MSG) ||
+            (remote_caps->ack_threshold == 0) ||
+            (cnx->ack_timeout == 0) ) {
                veth_error("Received incompatible capabilities from LPAR %d.\n",
                                cnx->remote_lp);
                return HvLpEvent_Rc_InvalidSubtypeData;
@@ -639,9 +639,11 @@ static int veth_process_caps(struct veth_lpar_connection *cnx)
 }
 
 /* FIXME: The gotos here are a bit dubious */
-static void veth_statemachine(void *p)
+static void veth_statemachine(struct work_struct *work)
 {
-       struct veth_lpar_connection *cnx = (struct veth_lpar_connection *)p;
+       struct veth_lpar_connection *cnx =
+               container_of(work, struct veth_lpar_connection,
+                            statemachine_wq.work);
        int rlp = cnx->remote_lp;
        int rc;
 
@@ -713,8 +715,8 @@ static void veth_statemachine(void *p)
                cnx->state |= VETH_STATE_OPEN;
        }
 
-       if ( (cnx->state & VETH_STATE_OPEN)
-            && !(cnx->state & VETH_STATE_SENTMON) ) {
+       if ( (cnx->state & VETH_STATE_OPEN) &&
+            !(cnx->state & VETH_STATE_SENTMON) ) {
                rc = veth_signalevent(cnx, VETH_EVENT_MONITOR,
                                      HvLpEvent_AckInd_DoAck,
                                      HvLpEvent_AckType_DeferredAck,
@@ -723,8 +725,8 @@ static void veth_statemachine(void *p)
                if (rc == HvLpEvent_Rc_Good) {
                        cnx->state |= VETH_STATE_SENTMON;
                } else {
-                       if ( (rc != HvLpEvent_Rc_PartitionDead)
-                            && (rc != HvLpEvent_Rc_PathClosed) )
+                       if ( (rc != HvLpEvent_Rc_PartitionDead) &&
+                            (rc != HvLpEvent_Rc_PathClosed) )
                                veth_error("Error sending monitor to LPAR %d, "
                                                "rc = %d\n", rlp, rc);
 
@@ -734,8 +736,8 @@ static void veth_statemachine(void *p)
                }
        }
 
-       if ( (cnx->state & VETH_STATE_OPEN)
-            && !(cnx->state & VETH_STATE_SENTCAPS)) {
+       if ( (cnx->state & VETH_STATE_OPEN) &&
+            !(cnx->state & VETH_STATE_SENTCAPS)) {
                u64 *rawcap = (u64 *)&cnx->local_caps;
 
                rc = veth_signalevent(cnx, VETH_EVENT_CAP,
@@ -747,8 +749,8 @@ static void veth_statemachine(void *p)
                if (rc == HvLpEvent_Rc_Good) {
                        cnx->state |= VETH_STATE_SENTCAPS;
                } else {
-                       if ( (rc != HvLpEvent_Rc_PartitionDead)
-                            && (rc != HvLpEvent_Rc_PathClosed) )
+                       if ( (rc != HvLpEvent_Rc_PartitionDead) &&
+                            (rc != HvLpEvent_Rc_PathClosed) )
                                veth_error("Error sending caps to LPAR %d, "
                                                "rc = %d\n", rlp, rc);
 
@@ -758,8 +760,8 @@ static void veth_statemachine(void *p)
                }
        }
 
-       if ((cnx->state & VETH_STATE_GOTCAPS)
-           && !(cnx->state & VETH_STATE_SENTCAPACK)) {
+       if ((cnx->state & VETH_STATE_GOTCAPS) &&
+           !(cnx->state & VETH_STATE_SENTCAPACK)) {
                struct veth_cap_data *remote_caps = &cnx->remote_caps;
 
                memcpy(remote_caps, &cnx->cap_event.u.caps_data,
@@ -782,9 +784,9 @@ static void veth_statemachine(void *p)
                        goto cant_cope;
        }
 
-       if ((cnx->state & VETH_STATE_GOTCAPACK)
-           && (cnx->state & VETH_STATE_GOTCAPS)
-           && !(cnx->state & VETH_STATE_READY)) {
+       if ((cnx->state & VETH_STATE_GOTCAPACK) &&
+           (cnx->state & VETH_STATE_GOTCAPS) &&
+           !(cnx->state & VETH_STATE_READY)) {
                if (cnx->cap_ack_event.base_event.xRc == HvLpEvent_Rc_Good) {
                        /* Start the ACK timer */
                        cnx->ack_timer.expires = jiffies + cnx->ack_timeout;
@@ -815,20 +817,19 @@ static int veth_init_connection(u8 rlp)
 {
        struct veth_lpar_connection *cnx;
        struct veth_msg *msgs;
-       int i, rc;
+       int i;
 
-       if ( (rlp == this_lp)
-            || ! HvLpConfig_doLpsCommunicateOnVirtualLan(this_lp, rlp) )
+       if ( (rlp == this_lp) ||
+            ! HvLpConfig_doLpsCommunicateOnVirtualLan(this_lp, rlp) )
                return 0;
 
-       cnx = kmalloc(sizeof(*cnx), GFP_KERNEL);
+       cnx = kzalloc(sizeof(*cnx), GFP_KERNEL);
        if (! cnx)
                return -ENOMEM;
-       memset(cnx, 0, sizeof(*cnx));
 
        cnx->remote_lp = rlp;
        spin_lock_init(&cnx->lock);
-       INIT_WORK(&cnx->statemachine_wq, veth_statemachine, cnx);
+       INIT_DELAYED_WORK(&cnx->statemachine_wq, veth_statemachine);
 
        init_timer(&cnx->ack_timer);
        cnx->ack_timer.function = veth_timed_ack;
@@ -845,20 +846,15 @@ static int veth_init_connection(u8 rlp)
 
        /* This gets us 1 reference, which is held on behalf of the driver
         * infrastructure. It's released at module unload. */
-       kobject_init(&cnx->kobject);
-       cnx->kobject.ktype = &veth_lpar_connection_ktype;
-       rc = kobject_set_name(&cnx->kobject, "cnx%.2d", rlp);
-       if (rc != 0)
-               return rc;
+       kobject_init(&cnx->kobject, &veth_lpar_connection_ktype);
 
-       msgs = kmalloc(VETH_NUMBUFFERS * sizeof(struct veth_msg), GFP_KERNEL);
+       msgs = kcalloc(VETH_NUMBUFFERS, sizeof(struct veth_msg), GFP_KERNEL);
        if (! msgs) {
                veth_error("Can't allocate buffers for LPAR %d.\n", rlp);
                return -ENOMEM;
        }
 
        cnx->msgs = msgs;
-       memset(msgs, 0, VETH_NUMBUFFERS * sizeof(struct veth_msg));
 
        for (i = 0; i < VETH_NUMBUFFERS; i++) {
                msgs[i].token = i;
@@ -937,9 +933,6 @@ static void veth_release_connection(struct kobject *kobj)
 
 static int veth_open(struct net_device *dev)
 {
-       struct veth_port *port = (struct veth_port *) dev->priv;
-
-       memset(&port->stats, 0, sizeof (port->stats));
        netif_start_queue(dev);
        return 0;
 }
@@ -950,13 +943,6 @@ static int veth_close(struct net_device *dev)
        return 0;
 }
 
-static struct net_device_stats *veth_get_stats(struct net_device *dev)
-{
-       struct veth_port *port = (struct veth_port *) dev->priv;
-
-       return &port->stats;
-}
-
 static int veth_change_mtu(struct net_device *dev, int new_mtu)
 {
        if ((new_mtu < 68) || (new_mtu > VETH_MAX_MTU))
@@ -967,25 +953,24 @@ static int veth_change_mtu(struct net_device *dev, int new_mtu)
 
 static void veth_set_multicast_list(struct net_device *dev)
 {
-       struct veth_port *port = (struct veth_port *) dev->priv;
+       struct veth_port *port = netdev_priv(dev);
        unsigned long flags;
 
        write_lock_irqsave(&port->mcast_gate, flags);
 
        if ((dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) ||
-                       (dev->mc_count > VETH_MAX_MCAST)) {
+                       (netdev_mc_count(dev) > VETH_MAX_MCAST)) {
                port->promiscuous = 1;
        } else {
-               struct dev_mc_list *dmi = dev->mc_list;
-               int i;
+               struct netdev_hw_addr *ha;
 
                port->promiscuous = 0;
 
                /* Update table */
                port->num_mcast = 0;
 
-               for (i = 0; i < dev->mc_count; i++) {
-                       u8 *addr = dmi->dmi_addr;
+               netdev_for_each_mc_addr(ha, dev) {
+                       u8 *addr = ha->addr;
                        u64 xaddr = 0;
 
                        if (addr[0] & 0x01) {/* multicast address? */
@@ -993,7 +978,6 @@ static void veth_set_multicast_list(struct net_device *dev)
                                port->mcast_addr[port->num_mcast] = xaddr;
                                port->num_mcast++;
                        }
-                       dmi = dmi->next;
                }
        }
 
@@ -1030,17 +1014,38 @@ static u32 veth_get_link(struct net_device *dev)
        return 1;
 }
 
-static struct ethtool_ops ops = {
+static const struct ethtool_ops ops = {
        .get_drvinfo = veth_get_drvinfo,
        .get_settings = veth_get_settings,
        .get_link = veth_get_link,
 };
 
-static struct net_device * __init veth_probe_one(int vlan, struct device *vdev)
+static const struct net_device_ops veth_netdev_ops = {
+       .ndo_open               = veth_open,
+       .ndo_stop               = veth_close,
+       .ndo_start_xmit         = veth_start_xmit,
+       .ndo_change_mtu         = veth_change_mtu,
+       .ndo_set_multicast_list = veth_set_multicast_list,
+       .ndo_set_mac_address    = NULL,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+static struct net_device *veth_probe_one(int vlan,
+               struct vio_dev *vio_dev)
 {
        struct net_device *dev;
        struct veth_port *port;
+       struct device *vdev = &vio_dev->dev;
        int i, rc;
+       const unsigned char *mac_addr;
+
+       mac_addr = vio_get_attribute(vio_dev, "local-mac-address", NULL);
+       if (mac_addr == NULL)
+               mac_addr = vio_get_attribute(vio_dev, "mac-address", NULL);
+       if (mac_addr == NULL) {
+               veth_error("Unable to fetch MAC address from device tree.\n");
+               return NULL;
+       }
 
        dev = alloc_etherdev(sizeof (struct veth_port));
        if (! dev) {
@@ -1048,7 +1053,7 @@ static struct net_device * __init veth_probe_one(int vlan, struct device *vdev)
                return NULL;
        }
 
-       port = (struct veth_port *) dev->priv;
+       port = netdev_priv(dev);
 
        spin_lock_init(&port->queue_lock);
        rwlock_init(&port->mcast_gate);
@@ -1065,24 +1070,13 @@ static struct net_device * __init veth_probe_one(int vlan, struct device *vdev)
        }
        port->dev = vdev;
 
-       dev->dev_addr[0] = 0x02;
-       dev->dev_addr[1] = 0x01;
-       dev->dev_addr[2] = 0xff;
-       dev->dev_addr[3] = vlan;
-       dev->dev_addr[4] = 0xff;
-       dev->dev_addr[5] = this_lp;
+       memcpy(dev->dev_addr, mac_addr, ETH_ALEN);
 
        dev->mtu = VETH_MAX_MTU;
 
-       memcpy(&port->mac_addr, dev->dev_addr, 6);
+       memcpy(&port->mac_addr, mac_addr, ETH_ALEN);
 
-       dev->open = veth_open;
-       dev->hard_start_xmit = veth_start_xmit;
-       dev->stop = veth_close;
-       dev->get_stats = veth_get_stats;
-       dev->change_mtu = veth_change_mtu;
-       dev->set_mac_address = NULL;
-       dev->set_multicast_list = veth_set_multicast_list;
+       dev->netdev_ops = &veth_netdev_ops;
        SET_ETHTOOL_OPS(dev, &ops);
 
        SET_NETDEV_DEV(dev, vdev);
@@ -1094,11 +1088,8 @@ static struct net_device * __init veth_probe_one(int vlan, struct device *vdev)
                return NULL;
        }
 
-       kobject_init(&port->kobject);
-       port->kobject.parent = &dev->class_dev.kobj;
-       port->kobject.ktype  = &veth_port_ktype;
-       kobject_set_name(&port->kobject, "veth_port");
-       if (0 != kobject_add(&port->kobject))
+       kobject_init(&port->kobject, &veth_port_ktype);
+       if (0 != kobject_add(&port->kobject, &dev->dev.kobj, "veth_port"))
                veth_error("Failed adding port for %s to sysfs.\n", dev->name);
 
        veth_info("%s attached to iSeries vlan %d (LPAR map = 0x%.4X)\n",
@@ -1115,7 +1106,7 @@ static int veth_transmit_to_one(struct sk_buff *skb, HvLpIndex rlp,
                                struct net_device *dev)
 {
        struct veth_lpar_connection *cnx = veth_cnx[rlp];
-       struct veth_port *port = (struct veth_port *) dev->priv;
+       struct veth_port *port = netdev_priv(dev);
        HvLpEvent_Rc rc;
        struct veth_msg *msg = NULL;
        unsigned long flags;
@@ -1141,7 +1132,7 @@ static int veth_transmit_to_one(struct sk_buff *skb, HvLpIndex rlp,
        msg->data.addr[0] = dma_map_single(port->dev, skb->data,
                                skb->len, DMA_TO_DEVICE);
 
-       if (dma_mapping_error(msg->data.addr[0]))
+       if (dma_mapping_error(port->dev, msg->data.addr[0]))
                goto recycle_and_drop;
 
        msg->dev = port->dev;
@@ -1178,7 +1169,6 @@ static void veth_transmit_to_many(struct sk_buff *skb,
                                          HvLpIndexMap lpmask,
                                          struct net_device *dev)
 {
-       struct veth_port *port = (struct veth_port *) dev->priv;
        int i, success, error;
 
        success = error = 0;
@@ -1194,18 +1184,18 @@ static void veth_transmit_to_many(struct sk_buff *skb,
        }
 
        if (error)
-               port->stats.tx_errors++;
+               dev->stats.tx_errors++;
 
        if (success) {
-               port->stats.tx_packets++;
-               port->stats.tx_bytes += skb->len;
+               dev->stats.tx_packets++;
+               dev->stats.tx_bytes += skb->len;
        }
 }
 
 static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        unsigned char *frame = skb->data;
-       struct veth_port *port = (struct veth_port *) dev->priv;
+       struct veth_port *port = netdev_priv(dev);
        HvLpIndexMap lpmask;
 
        if (! (frame[0] & 0x01)) {
@@ -1214,7 +1204,7 @@ static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
                if ( ! ((1 << rlp) & port->lpar_map) ) {
                        dev_kfree_skb(skb);
-                       return 0;
+                       return NETDEV_TX_OK;
                }
 
                lpmask = 1 << rlp;
@@ -1226,7 +1216,7 @@ static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        dev_kfree_skb(skb);
 
-       return 0;
+       return NETDEV_TX_OK;
 }
 
 /* You must hold the connection's lock when you call this function. */
@@ -1240,7 +1230,7 @@ static void veth_recycle_msg(struct veth_lpar_connection *cnx,
                dma_address = msg->data.addr[0];
                dma_length = msg->data.len[0];
 
-               if (!dma_mapping_error(dma_address))
+               if (!dma_mapping_error(msg->dev, dma_address))
                        dma_unmap_single(msg->dev, dma_address, dma_length,
                                        DMA_TO_DEVICE);
 
@@ -1269,7 +1259,7 @@ static void veth_wake_queues(struct veth_lpar_connection *cnx)
                if (! dev)
                        continue;
 
-               port = (struct veth_port *)dev->priv;
+               port = netdev_priv(dev);
 
                if (! (port->lpar_map & (1<<cnx->remote_lp)))
                        continue;
@@ -1298,7 +1288,7 @@ static void veth_stop_queues(struct veth_lpar_connection *cnx)
                if (! dev)
                        continue;
 
-               port = (struct veth_port *)dev->priv;
+               port = netdev_priv(dev);
 
                /* If this cnx is not on the vlan for this port, continue */
                if (! (port->lpar_map & (1 << cnx->remote_lp)))
@@ -1393,7 +1383,7 @@ static inline void veth_build_dma_list(struct dma_chunk *list,
        unsigned long done;
        int i = 1;
 
-       /* FIXME: skbs are continguous in real addresses.  Do we
+       /* FIXME: skbs are contiguous in real addresses.  Do we
         * really need to break it into PAGE_SIZE chunks, or can we do
         * it just at the granularity of iSeries real->absolute
         * mapping?  Indeed, given the way the allocator works, can we
@@ -1520,7 +1510,7 @@ static void veth_receive(struct veth_lpar_connection *cnx,
                        continue;
                }
 
-               port = (struct veth_port *)dev->priv;
+               port = netdev_priv(dev);
                dest = *((u64 *) skb->data) & 0xFFFFFFFFFFFF0000;
 
                if ((vlan > HVMAXARCHITECTEDVIRTUALLANS) || !port) {
@@ -1533,12 +1523,11 @@ static void veth_receive(struct veth_lpar_connection *cnx,
                }
 
                skb_put(skb, length);
-               skb->dev = dev;
                skb->protocol = eth_type_trans(skb, dev);
                skb->ip_summed = CHECKSUM_NONE;
                netif_rx(skb);  /* send it up */
-               port->stats.rx_packets++;
-               port->stats.rx_bytes += length;
+               dev->stats.rx_packets++;
+               dev->stats.rx_bytes += length;
        } while (startchunk += nchunks, startchunk < VETH_MAX_FRAMES_PER_MSG);
 
        /* Ack it */
@@ -1548,8 +1537,8 @@ static void veth_receive(struct veth_lpar_connection *cnx,
        cnx->pending_acks[cnx->num_pending_acks++] =
                event->base_event.xCorrelationToken;
 
-       if ( (cnx->num_pending_acks >= cnx->remote_caps.ack_threshold)
-            || (cnx->num_pending_acks >= VETH_MAX_ACKS_PER_MSG) )
+       if ( (cnx->num_pending_acks >= cnx->remote_caps.ack_threshold) ||
+            (cnx->num_pending_acks >= VETH_MAX_ACKS_PER_MSG) )
                veth_flush_acks(cnx);
 
        spin_unlock_irqrestore(&cnx->lock, flags);
@@ -1609,7 +1598,7 @@ static int veth_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        struct net_device *dev;
        struct veth_port *port;
 
-       dev = veth_probe_one(i, &vdev->dev);
+       dev = veth_probe_one(i, vdev);
        if (dev == NULL) {
                veth_remove(vdev);
                return 1;
@@ -1642,7 +1631,7 @@ static int veth_probe(struct vio_dev *vdev, const struct vio_device_id *id)
  * support.
  */
 static struct vio_device_id veth_device_table[] __devinitdata = {
-       { "vlan", "" },
+       { "network", "IBM,iSeries-l-lan" },
        { "", "" }
 };
 MODULE_DEVICE_TABLE(vio, veth_device_table);
@@ -1661,7 +1650,7 @@ static struct vio_driver veth_driver = {
  * Module initialization/cleanup
  */
 
-void __exit veth_module_cleanup(void)
+static void __exit veth_module_cleanup(void)
 {
        int i;
        struct veth_lpar_connection *cnx;
@@ -1690,11 +1679,14 @@ void __exit veth_module_cleanup(void)
 }
 module_exit(veth_module_cleanup);
 
-int __init veth_module_init(void)
+static int __init veth_module_init(void)
 {
        int i;
        int rc;
 
+       if (!firmware_has_feature(FW_FEATURE_ISERIES))
+               return -ENODEV;
+
        this_lp = HvLpConfig_getLpIndex_outline();
 
        for (i = 0; i < HVMAXARCHITECTEDLPS; ++i) {
@@ -1717,9 +1709,9 @@ int __init veth_module_init(void)
                        continue;
 
                kobj = &veth_cnx[i]->kobject;
-               kobj->parent = &veth_driver.driver.kobj;
                /* If the add failes, complain but otherwise continue */
-               if (0 != kobject_add(kobj))
+               if (0 != driver_add_kobj(&veth_driver.driver, kobj,
+                                       "cnx%.2d", veth_cnx[i]->remote_lp))
                        veth_error("cnx %d: Failed adding to sysfs.\n", i);
        }