Commit 31bdc5dc authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6

* 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/sparc-2.6:
  [SPARC64]: Set vio->desc_buf to NULL after freeing.
  [SPARC]: Mark sparc and sparc64 as not having virt_to_bus
  [SPARC64]: Fix reset handling in VNET driver.
  [SPARC64]: Handle reset events in vio_link_state_change().
  [SPARC64]: Handle LDC resets properly in domain-services driver.
  [SPARC64]: Massively simplify VIO device layer and support hot add/remove.
  [SPARC64]: Simplify VNET probing.
  [SPARC64]: Simplify VDC device probing.
  [SPARC64]: Add basic infrastructure for MD add/remove notification.
parents 5cc97bf2 a5f8967e
...@@ -21,6 +21,9 @@ config GENERIC_ISA_DMA ...@@ -21,6 +21,9 @@ config GENERIC_ISA_DMA
bool bool
default y default y
config ARCH_NO_VIRT_TO_BUS
def_bool y
source "init/Kconfig" source "init/Kconfig"
menu "General machine setup" menu "General machine setup"
......
...@@ -62,6 +62,9 @@ config AUDIT_ARCH ...@@ -62,6 +62,9 @@ config AUDIT_ARCH
bool bool
default y default y
config ARCH_NO_VIRT_TO_BUS
def_bool y
choice choice
prompt "Kernel page size" prompt "Kernel page size"
default SPARC64_PAGE_SIZE_8KB default SPARC64_PAGE_SIZE_8KB
......
...@@ -1013,6 +1013,19 @@ static void ds_up(struct ds_info *dp) ...@@ -1013,6 +1013,19 @@ static void ds_up(struct ds_info *dp)
dp->hs_state = DS_HS_START; dp->hs_state = DS_HS_START;
} }
static void ds_reset(struct ds_info *dp)
{
int i;
dp->hs_state = 0;
for (i = 0; i < ARRAY_SIZE(ds_states); i++) {
struct ds_cap_state *cp = &ds_states[i];
cp->state = CAP_STATE_UNKNOWN;
}
}
static void ds_event(void *arg, int event) static void ds_event(void *arg, int event)
{ {
struct ds_info *dp = arg; struct ds_info *dp = arg;
...@@ -1028,6 +1041,12 @@ static void ds_event(void *arg, int event) ...@@ -1028,6 +1041,12 @@ static void ds_event(void *arg, int event)
return; return;
} }
if (event == LDC_EVENT_RESET) {
ds_reset(dp);
spin_unlock_irqrestore(&ds_lock, flags);
return;
}
if (event != LDC_EVENT_DATA_READY) { if (event != LDC_EVENT_DATA_READY) {
printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event); printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event);
spin_unlock_irqrestore(&ds_lock, flags); spin_unlock_irqrestore(&ds_lock, flags);
......
...@@ -137,7 +137,7 @@ static struct mdesc_handle *mdesc_kmalloc(unsigned int mdesc_size) ...@@ -137,7 +137,7 @@ static struct mdesc_handle *mdesc_kmalloc(unsigned int mdesc_size)
sizeof(struct mdesc_hdr) + sizeof(struct mdesc_hdr) +
mdesc_size); mdesc_size);
base = kmalloc(handle_size + 15, GFP_KERNEL); base = kmalloc(handle_size + 15, GFP_KERNEL | __GFP_NOFAIL);
if (base) { if (base) {
struct mdesc_handle *hp; struct mdesc_handle *hp;
unsigned long addr; unsigned long addr;
...@@ -214,18 +214,83 @@ void mdesc_release(struct mdesc_handle *hp) ...@@ -214,18 +214,83 @@ void mdesc_release(struct mdesc_handle *hp)
} }
EXPORT_SYMBOL(mdesc_release); EXPORT_SYMBOL(mdesc_release);
static DEFINE_MUTEX(mdesc_mutex);
static struct mdesc_notifier_client *client_list;
void mdesc_register_notifier(struct mdesc_notifier_client *client)
{
u64 node;
mutex_lock(&mdesc_mutex);
client->next = client_list;
client_list = client;
mdesc_for_each_node_by_name(cur_mdesc, node, client->node_name)
client->add(cur_mdesc, node);
mutex_unlock(&mdesc_mutex);
}
/* Run 'func' on nodes which are in A but not in B. */
static void invoke_on_missing(const char *name,
struct mdesc_handle *a,
struct mdesc_handle *b,
void (*func)(struct mdesc_handle *, u64))
{
u64 node;
mdesc_for_each_node_by_name(a, node, name) {
const u64 *id = mdesc_get_property(a, node, "id", NULL);
int found = 0;
u64 fnode;
mdesc_for_each_node_by_name(b, fnode, name) {
const u64 *fid = mdesc_get_property(b, fnode,
"id", NULL);
if (*id == *fid) {
found = 1;
break;
}
}
if (!found)
func(a, node);
}
}
static void notify_one(struct mdesc_notifier_client *p,
struct mdesc_handle *old_hp,
struct mdesc_handle *new_hp)
{
invoke_on_missing(p->node_name, old_hp, new_hp, p->remove);
invoke_on_missing(p->node_name, new_hp, old_hp, p->add);
}
static void mdesc_notify_clients(struct mdesc_handle *old_hp,
struct mdesc_handle *new_hp)
{
struct mdesc_notifier_client *p = client_list;
while (p) {
notify_one(p, old_hp, new_hp);
p = p->next;
}
}
void mdesc_update(void) void mdesc_update(void)
{ {
unsigned long len, real_len, status; unsigned long len, real_len, status;
struct mdesc_handle *hp, *orig_hp; struct mdesc_handle *hp, *orig_hp;
unsigned long flags; unsigned long flags;
mutex_lock(&mdesc_mutex);
(void) sun4v_mach_desc(0UL, 0UL, &len); (void) sun4v_mach_desc(0UL, 0UL, &len);
hp = mdesc_alloc(len, &kmalloc_mdesc_memops); hp = mdesc_alloc(len, &kmalloc_mdesc_memops);
if (!hp) { if (!hp) {
printk(KERN_ERR "MD: mdesc alloc fails\n"); printk(KERN_ERR "MD: mdesc alloc fails\n");
return; goto out;
} }
status = sun4v_mach_desc(__pa(&hp->mdesc), len, &real_len); status = sun4v_mach_desc(__pa(&hp->mdesc), len, &real_len);
...@@ -234,18 +299,25 @@ void mdesc_update(void) ...@@ -234,18 +299,25 @@ void mdesc_update(void)
status); status);
atomic_dec(&hp->refcnt); atomic_dec(&hp->refcnt);
mdesc_free(hp); mdesc_free(hp);
return; goto out;
} }
spin_lock_irqsave(&mdesc_lock, flags); spin_lock_irqsave(&mdesc_lock, flags);
orig_hp = cur_mdesc; orig_hp = cur_mdesc;
cur_mdesc = hp; cur_mdesc = hp;
spin_unlock_irqrestore(&mdesc_lock, flags);
mdesc_notify_clients(orig_hp, hp);
spin_lock_irqsave(&mdesc_lock, flags);
if (atomic_dec_and_test(&orig_hp->refcnt)) if (atomic_dec_and_test(&orig_hp->refcnt))
mdesc_free(orig_hp); mdesc_free(orig_hp);
else else
list_add(&orig_hp->list, &mdesc_zombie_list); list_add(&orig_hp->list, &mdesc_zombie_list);
spin_unlock_irqrestore(&mdesc_lock, flags); spin_unlock_irqrestore(&mdesc_lock, flags);
out:
mutex_unlock(&mdesc_mutex);
} }
static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc) static struct mdesc_elem *node_block(struct mdesc_hdr *mdesc)
......
...@@ -201,10 +201,11 @@ static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp, ...@@ -201,10 +201,11 @@ static void vio_fill_channel_info(struct mdesc_handle *hp, u64 mp,
static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
struct device *parent) struct device *parent)
{ {
const char *type, *compat; const char *type, *compat, *bus_id_name;
struct device_node *dp; struct device_node *dp;
struct vio_dev *vdev; struct vio_dev *vdev;
int err, tlen, clen; int err, tlen, clen;
const u64 *id;
type = mdesc_get_property(hp, mp, "device-type", &tlen); type = mdesc_get_property(hp, mp, "device-type", &tlen);
if (!type) { if (!type) {
...@@ -220,6 +221,16 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, ...@@ -220,6 +221,16 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
return NULL; return NULL;
} }
bus_id_name = type;
if (!strcmp(type, "domain-services-port"))
bus_id_name = "ds";
if (strlen(bus_id_name) >= KOBJ_NAME_LEN - 4) {
printk(KERN_ERR "VIO: bus_id_name [%s] is too long.\n",
bus_id_name);
return NULL;
}
compat = mdesc_get_property(hp, mp, "device-type", &clen); compat = mdesc_get_property(hp, mp, "device-type", &clen);
if (!compat) { if (!compat) {
clen = 0; clen = 0;
...@@ -249,7 +260,14 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, ...@@ -249,7 +260,14 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
vio_fill_channel_info(hp, mp, vdev); vio_fill_channel_info(hp, mp, vdev);
snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%lx", mp); id = mdesc_get_property(hp, mp, "id", NULL);
if (!id)
snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s",
bus_id_name);
else
snprintf(vdev->dev.bus_id, BUS_ID_SIZE, "%s-%lu",
bus_id_name, *id);
vdev->dev.parent = parent; vdev->dev.parent = parent;
vdev->dev.bus = &vio_bus_type; vdev->dev.bus = &vio_bus_type;
vdev->dev.release = vio_dev_release; vdev->dev.release = vio_dev_release;
...@@ -269,6 +287,8 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, ...@@ -269,6 +287,8 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
} }
vdev->dp = dp; vdev->dp = dp;
printk(KERN_ERR "VIO: Adding device %s\n", vdev->dev.bus_id);
err = device_register(&vdev->dev); err = device_register(&vdev->dev);
if (err) { if (err) {
printk(KERN_ERR "VIO: Could not register device %s, err=%d\n", printk(KERN_ERR "VIO: Could not register device %s, err=%d\n",
...@@ -283,46 +303,46 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp, ...@@ -283,46 +303,46 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
return vdev; return vdev;
} }
static void walk_tree(struct mdesc_handle *hp, u64 n, struct vio_dev *parent) static void vio_add(struct mdesc_handle *hp, u64 node)
{ {
u64 a; (void) vio_create_one(hp, node, &root_vdev->dev);
mdesc_for_each_arc(a, hp, n, MDESC_ARC_TYPE_FWD) {
struct vio_dev *vdev;
u64 target;
target = mdesc_arc_target(hp, a);
vdev = vio_create_one(hp, target, &parent->dev);
if (vdev)
walk_tree(hp, target, vdev);
}
} }
static void create_devices(struct mdesc_handle *hp, u64 root) static int vio_md_node_match(struct device *dev, void *arg)
{ {
u64 mp; struct vio_dev *vdev = to_vio_dev(dev);
root_vdev = vio_create_one(hp, root, NULL); if (vdev->mp == (u64) arg)
if (!root_vdev) { return 1;
printk(KERN_ERR "VIO: Coult not create root device.\n");
return;
}
walk_tree(hp, root, root_vdev); return 0;
}
static void vio_remove(struct mdesc_handle *hp, u64 node)
{
struct device *dev;
/* Domain services is odd as it doesn't sit underneath the dev = device_find_child(&root_vdev->dev, (void *) node,
* channel-devices node, so we plug it in manually. vio_md_node_match);
*/ if (dev) {
mp = mdesc_node_by_name(hp, MDESC_NODE_NULL, "domain-services"); printk(KERN_INFO "VIO: Removing device %s\n", dev->bus_id);
if (mp != MDESC_NODE_NULL) {
struct vio_dev *parent = vio_create_one(hp, mp,
&root_vdev->dev);
if (parent) device_unregister(dev);
walk_tree(hp, mp, parent);
} }
} }
static struct mdesc_notifier_client vio_device_notifier = {
.add = vio_add,
.remove = vio_remove,
.node_name = "virtual-device-port",
};
static struct mdesc_notifier_client vio_ds_notifier = {
.add = vio_add,
.remove = vio_remove,
.node_name = "domain-services-port",
};
const char *channel_devices_node = "channel-devices"; const char *channel_devices_node = "channel-devices";
const char *channel_devices_compat = "SUNW,sun4v-channel-devices"; const char *channel_devices_compat = "SUNW,sun4v-channel-devices";
const char *cfg_handle_prop = "cfg-handle"; const char *cfg_handle_prop = "cfg-handle";
...@@ -381,11 +401,19 @@ static int __init vio_init(void) ...@@ -381,11 +401,19 @@ static int __init vio_init(void)
cdev_cfg_handle = *cfg_handle; cdev_cfg_handle = *cfg_handle;
create_devices(hp, root); root_vdev = vio_create_one(hp, root, NULL);
err = -ENODEV;
if (!root_vdev) {
printk(KERN_ERR "VIO: Coult not create root device.\n");
goto out_release;
}
mdesc_register_notifier(&vio_device_notifier);
mdesc_register_notifier(&vio_ds_notifier);
mdesc_release(hp); mdesc_release(hp);
return 0; return err;
out_release: out_release:
mdesc_release(hp); mdesc_release(hp);
......
...@@ -78,6 +78,24 @@ static int start_handshake(struct vio_driver_state *vio) ...@@ -78,6 +78,24 @@ static int start_handshake(struct vio_driver_state *vio)
return 0; return 0;
} }
static void flush_rx_dring(struct vio_driver_state *vio)
{
struct vio_dring_state *dr;
u64 ident;
BUG_ON(!(vio->dr_state & VIO_DR_STATE_RXREG));
dr = &vio->drings[VIO_DRIVER_RX_RING];
ident = dr->ident;
BUG_ON(!vio->desc_buf);
kfree(vio->desc_buf);
vio->desc_buf = NULL;
memset(dr, 0, sizeof(*dr));
dr->ident = ident;
}
void vio_link_state_change(struct vio_driver_state *vio, int event) void vio_link_state_change(struct vio_driver_state *vio, int event)
{ {
if (event == LDC_EVENT_UP) { if (event == LDC_EVENT_UP) {
...@@ -98,6 +116,16 @@ void vio_link_state_change(struct vio_driver_state *vio, int event) ...@@ -98,6 +116,16 @@ void vio_link_state_change(struct vio_driver_state *vio, int event)
break; break;
} }
start_handshake(vio); start_handshake(vio);
} else if (event == LDC_EVENT_RESET) {
vio->hs_state = VIO_HS_INVALID;
if (vio->dr_state & VIO_DR_STATE_RXREG)
flush_rx_dring(vio);
vio->dr_state = 0x00;
memset(&vio->ver, 0, sizeof(vio->ver));
ldc_disconnect(vio->lp);
} }
} }
EXPORT_SYMBOL(vio_link_state_change); EXPORT_SYMBOL(vio_link_state_change);
...@@ -396,6 +424,8 @@ static int process_dreg_info(struct vio_driver_state *vio, ...@@ -396,6 +424,8 @@ static int process_dreg_info(struct vio_driver_state *vio,
if (vio->dr_state & VIO_DR_STATE_RXREG) if (vio->dr_state & VIO_DR_STATE_RXREG)
goto send_nack; goto send_nack;
BUG_ON(vio->desc_buf);
vio->desc_buf = kzalloc(pkt->descr_size, GFP_ATOMIC); vio->desc_buf = kzalloc(pkt->descr_size, GFP_ATOMIC);
if (!vio->desc_buf) if (!vio->desc_buf)
goto send_nack; goto send_nack;
......
...@@ -45,8 +45,6 @@ struct vdc_req_entry { ...@@ -45,8 +45,6 @@ struct vdc_req_entry {
struct vdc_port { struct vdc_port {
struct vio_driver_state vio; struct vio_driver_state vio;
struct vdc *vp;
struct gendisk *disk; struct gendisk *disk;
struct vdc_completion *cmp; struct vdc_completion *cmp;
...@@ -72,8 +70,6 @@ struct vdc_port { ...@@ -72,8 +70,6 @@ struct vdc_port {
struct vio_disk_geom geom; struct vio_disk_geom geom;
struct vio_disk_vtoc label; struct vio_disk_vtoc label;
struct list_head list;
}; };
static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio) static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio)
...@@ -81,15 +77,6 @@ static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio) ...@@ -81,15 +77,6 @@ static inline struct vdc_port *to_vdc_port(struct vio_driver_state *vio)
return container_of(vio, struct vdc_port, vio); return container_of(vio, struct vdc_port, vio);
} }
struct vdc {
/* Protects prot_list. */
spinlock_t lock;
struct vio_dev *dev;
struct list_head port_list;
};
/* Ordered from largest major to lowest */ /* Ordered from largest major to lowest */
static struct vio_version vdc_versions[] = { static struct vio_version vdc_versions[] = {
{ .major = 1, .minor = 0 }, { .major = 1, .minor = 0 },
...@@ -747,21 +734,23 @@ static struct vio_driver_ops vdc_vio_ops = { ...@@ -747,21 +734,23 @@ static struct vio_driver_ops vdc_vio_ops = {
.handshake_complete = vdc_handshake_complete, .handshake_complete = vdc_handshake_complete,
}; };
static void print_version(void)
{
static int version_printed;
if (version_printed++ == 0)
printk(KERN_INFO "%s", version);
}
static int __devinit vdc_port_probe(struct vio_dev *vdev, static int __devinit vdc_port_probe(struct vio_dev *vdev,
const struct vio_device_id *id) const struct vio_device_id *id)
{ {
struct mdesc_handle *hp; struct mdesc_handle *hp;
struct vdc_port *port; struct vdc_port *port;
unsigned long flags;
struct vdc *vp;
const u64 *port_id; const u64 *port_id;
int err; int err;
vp = dev_get_drvdata(vdev->dev.parent); print_version();
if (!vp) {
printk(KERN_ERR PFX "Cannot find port parent vdc.\n");
return -ENODEV;
}
hp = mdesc_grab(); hp = mdesc_grab();
...@@ -783,7 +772,6 @@ static int __devinit vdc_port_probe(struct vio_dev *vdev, ...@@ -783,7 +772,6 @@ static int __devinit vdc_port_probe(struct vio_dev *vdev,
goto err_out_release_mdesc; goto err_out_release_mdesc;
} }
port->vp = vp;
port->dev_no = *port_id; port->dev_no = *port_id;
if (port->dev_no >= 26) if (port->dev_no >= 26)
...@@ -818,12 +806,6 @@ static int __devinit vdc_port_probe(struct vio_dev *vdev, ...@@ -818,12 +806,6 @@ static int __devinit vdc_port_probe(struct vio_dev *vdev,
if (err) if (err)
goto err_out_free_tx_ring; goto err_out_free_tx_ring;
INIT_LIST_HEAD(&port->list);
spin_lock_irqsave(&vp->lock, flags);
list_add(&port->list, &vp->port_list);
spin_unlock_irqrestore(&vp->lock, flags);
dev_set_drvdata(&vdev->dev, port); dev_set_drvdata(&vdev->dev, port);
mdesc_release(hp); mdesc_release(hp);
...@@ -879,58 +861,6 @@ static struct vio_driver vdc_port_driver = { ...@@ -879,58 +861,6 @@ static struct vio_driver vdc_port_driver = {
} }
}; };
static int __devinit vdc_probe(struct vio_dev *vdev,
const struct vio_device_id *id)
{
static int vdc_version_printed;
struct vdc *vp;
if (vdc_version_printed++ == 0)
printk(KERN_INFO "%s", version);
vp = kzalloc(sizeof(struct vdc), GFP_KERNEL);
if (!vp)
return -ENOMEM;
spin_lock_init(&vp->lock);
vp->dev = vdev;
INIT_LIST_HEAD(&vp->port_list);
dev_set_drvdata(&vdev->dev, vp);
return 0;
}
static int vdc_remove(struct vio_dev *vdev)
{
struct vdc *vp = dev_get_drvdata(&vdev->dev);
if (vp) {
kfree(vp);
dev_set_drvdata(&vdev->dev, NULL);
}
return 0;
}
static struct vio_device_id vdc_match[] = {
{
.type = "block",
},
{},
};
MODULE_DEVICE_TABLE(vio, vdc_match);
static struct vio_driver vdc_driver = {
.id_table = vdc_match,
.probe = vdc_probe,
.remove = vdc_remove,
.driver = {
.name = "vdc",
.owner = THIS_MODULE,
}
};
static int __init vdc_init(void) static int __init vdc_init(void)
{ {
int err; int err;
...@@ -940,19 +870,13 @@ static int __init vdc_init(void) ...@@ -940,19 +870,13 @@ static int __init vdc_init(void)
goto out_err; goto out_err;
vdc_major = err; vdc_major = err;
err = vio_register_driver(&vdc_driver);
if (err)
goto out_unregister_blkdev;
err = vio_register_driver(&vdc_port_driver); err = vio_register_driver(&vdc_port_driver);
if (err) if (err)
goto out_unregister_vdc; goto out_unregister_blkdev;
return 0; return 0;
out_unregister_vdc:
vio_unregister_driver(&vdc_driver);
out_unregister_blkdev: out_unregister_blkdev:
unregister_blkdev(vdc_major, VDCBLK_NAME); unregister_blkdev(vdc_major, VDCBLK_NAME);
vdc_major = 0; vdc_major = 0;
...@@ -964,7 +888,6 @@ out_err: ...@@ -964,7 +888,6 @@ out_err:
static void __exit vdc_exit(void) static void __exit vdc_exit(void)
{ {
vio_unregister_driver(&vdc_port_driver); vio_unregister_driver(&vdc_port_driver);
vio_unregister_driver(&vdc_driver);
unregister_blkdev(vdc_major, VDCBLK_NAME); unregister_blkdev(vdc_major, VDCBLK_NAME);
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/ethtool.h> #include <linux/ethtool.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/mutex.h>
#include <asm/vio.h> #include <asm/vio.h>
#include <asm/ldc.h> #include <asm/ldc.h>
...@@ -497,6 +498,8 @@ static void vnet_event(void *arg, int event) ...@@ -497,6 +498,8 @@ static void vnet_event(void *arg, int event)
vio_link_state_change(vio, event); vio_link_state_change(vio, event);
spin_unlock_irqrestore(&vio->lock, flags); spin_unlock_irqrestore(&vio->lock, flags);
if (event == LDC_EVENT_RESET)
vio_port_up(vio);
return; return;
} }
...@@ -875,6 +878,115 @@ err_out: ...@@ -875,6 +878,115 @@ err_out:
return err; return err;
} }
static LIST_HEAD(vnet_list);
static DEFINE_MUTEX(vnet_list_mutex);
static struct vnet * __devinit vnet_new(const u64 *local_mac)
{
struct net_device *dev;
struct vnet *vp;
int err, i;
dev = alloc_etherdev(sizeof(*vp));
if (!dev) {
printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
return ERR_PTR(-ENOMEM);
}
for (i = 0; i < ETH_ALEN; i++)
dev->dev_addr[i] = (*local_mac >> (5 - i) * 8) & 0xff;
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
vp = netdev_priv(dev);
spin_lock_init(&vp->lock);
vp->dev = dev;
INIT_LIST_HEAD(&vp->port_list);
for (i = 0; i < VNET_PORT_HASH_SIZE; i++)
INIT_HLIST_HEAD(&vp->port_hash[i]);
INIT_LIST_HEAD(&vp->list);
vp->local_mac = *local_mac;
dev->open = vnet_open;
dev->stop = vnet_close;
dev->set_multicast_list = vnet_set_rx_mode;
dev->set_mac_address = vnet_set_mac_addr;
dev->tx_timeout = vnet_tx_timeout;
dev->ethtool_ops = &vnet_ethtool_ops;
dev->watchdog_timeo = VNET_TX_TIMEOUT;
dev->change_mtu = vnet_change_mtu;
dev->hard_start_xmit = vnet_start_xmit;
err = register_netdev(dev);
if (err) {
printk(KERN_ERR PFX "Cannot register net device, "
"aborting.\n");
goto err_out_free_dev;
}
printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name);
for (i = 0; i < 6; i++)
printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
list_add(&vp->list, &vnet_list);
return vp;
err_out_free_dev:
free_netdev(dev);
return ERR_PTR(err);
}
static struct vnet * __devinit vnet_find_or_create(const u64 *local_mac)
{
struct vnet *iter, *vp;
mutex_lock(&vnet_list_mutex);
vp = NULL;
list_for_each_entry(iter, &vnet_list, list) {
if (iter->local_mac == *local_mac) {
vp = iter;
break;
}
}
if (!vp)
vp = vnet_new(local_mac);
mutex_unlock(&vnet_list_mutex);
return vp;
}
static const char *local_mac_prop = "local-mac-address";
static struct vnet * __devinit vnet_find_parent(struct mdesc_handle *hp,
u64 port_node)
{
const u64 *local_mac = NULL;
u64 a;
mdesc_for_each_arc(a, hp, port_node, MDESC_ARC_TYPE_BACK) {
u64 target = mdesc_arc_target(hp, a);
const char *name;
name = mdesc_get_property(hp, target, "name", NULL);
if (!name || strcmp(name, "network"))
continue;
local_mac = mdesc_get_property(hp, target,
local_mac_prop, NULL);
if (local_mac)
break;
}
if (!local_mac)
return ERR_PTR(-ENODEV);
return vnet_find_or_create(local_mac);
}
static struct ldc_channel_config vnet_ldc_cfg = { static struct ldc_channel_config vnet_ldc_cfg = {
.event = vnet_event, .event = vnet_event,
.mtu = 64, .mtu = 64,
...@@ -887,6 +999,14 @@ static struct vio_driver_ops vnet_vio_ops = { ...@@ -887,6 +999,14 @@ static struct vio_driver_ops vnet_vio_ops = {
.handshake_complete = vnet_handshake_complete, .handshake_complete = vnet_handshake_complete,
}; };
static void print_version(void)
{
static int version_printed;
if (version_printed++ == 0)
printk(KERN_INFO "%s", version);
}
const char *remote_macaddr_prop = "remote-mac-address"; const char *remote_macaddr_prop = "remote-mac-address";
static int __devinit vnet_port_probe(struct vio_dev *vdev, static int __devinit vnet_port_probe(struct vio_dev *vdev,
...@@ -899,14 +1019,17 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev, ...@@ -899,14 +1019,17 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev,
const u64 *rmac; const u64 *rmac;
int len, i, err, switch_port; int len, i, err, switch_port;
vp = dev_get_drvdata(vdev->dev.parent); print_version();
if (!vp) {
printk(KERN_ERR PFX "Cannot find port parent vnet.\n");
return -ENODEV;
}
hp = mdesc_grab(); hp = mdesc_grab();
vp = vnet_find_parent(hp, vdev->mp);
if (IS_ERR(vp)) {
printk(KERN_ERR PFX "Cannot find port parent vnet.\n");
err = PTR_ERR(vp);
goto err_out_put_mdesc;
}
rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len); rmac = mdesc_get_property(hp, vdev->mp, remote_macaddr_prop, &len);
err = -ENODEV; err = -ENODEV;
if (!rmac) { if (!rmac) {
...@@ -1025,139 +1148,14 @@ static struct vio_driver vnet_port_driver = { ...@@ -1025,139 +1148,14 @@ static struct vio_driver vnet_port_driver = {
} }
}; };
const char *local_mac_prop = "local-mac-address";
static int __devinit vnet_probe(struct vio_dev *vdev,
const struct vio_device_id *id)
{
static int vnet_version_printed;
struct mdesc_handle *hp;
struct net_device *dev;
struct vnet *vp;
const u64 *mac;
int err, i, len;
if (vnet_version_printed++ == 0)
printk(KERN_INFO "%s", version);
hp = mdesc_grab();
mac = mdesc_get_property(hp, vdev->mp, local_mac_prop, &len);
if (!mac) {
printk(KERN_ERR PFX "vnet lacks %s property.\n",
local_mac_prop);
err = -ENODEV;
goto err_out;
}
dev = alloc_etherdev(sizeof(*vp));
if (!dev) {
printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n");
err = -ENOMEM;
goto err_out;
}
for (i = 0; i < ETH_ALEN; i++)
dev->dev_addr[i] = (*mac >> (5 - i) * 8) & 0xff;
memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len);
SET_NETDEV_DEV(dev, &vdev->dev);
vp = netdev_priv(dev);
spin_lock_init(&vp->lock);
vp->dev = dev;
vp->vdev = vdev;
INIT_LIST_HEAD(&vp->port_list);
for (i = 0; i < VNET_PORT_HASH_SIZE; i++)
INIT_HLIST_HEAD(&vp->port_hash[i]);
dev->open = vnet_open;
dev->stop = vnet_close;
dev->set_multicast_list = vnet_set_rx_mode;
dev->set_mac_address = vnet_set_mac_addr;
dev->tx_timeout = vnet_tx_timeout;
dev->ethtool_ops = &vnet_ethtool_ops;
dev->watchdog_timeo = VNET_TX_TIMEOUT;
dev->change_mtu = vnet_change_mtu;
dev->hard_start_xmit = vnet_start_xmit;
err = register_netdev(dev);
if (err) {
printk(KERN_ERR PFX "Cannot register net device, "
"aborting.\n");
goto err_out_free_dev;
}
printk(KERN_INFO "%s: Sun LDOM vnet ", dev->name);
for (i = 0; i < 6; i++)
printk("%2.2x%c", dev->dev_addr[i], i == 5 ? '\n' : ':');
dev_set_drvdata(&vdev->dev, vp);
mdesc_release(hp);
return 0;
err_out_free_dev:
free_netdev(dev);
err_out:
mdesc_release(hp);
return err;
}
static int vnet_remove(struct vio_dev *vdev)
{
struct vnet *vp = dev_get_drvdata(&vdev->dev);
if (vp) {
/* XXX unregister port, or at least check XXX */
unregister_netdevice(vp->dev);
dev_set_drvdata(&vdev->dev, NULL);
}
return 0;
}
static struct vio_device_id vnet_match[] = {
{
.type = "network",
},
{},
};
MODULE_DEVICE_TABLE(vio, vnet_match);
static struct vio_driver vnet_driver = {
.id_table = vnet_match,
.probe = vnet_probe,
.remove = vnet_remove,
.driver = {
.name = "vnet",
.owner = THIS_MODULE,
}
};
static int __init vnet_init(void) static int __init vnet_init(void)
{ {
int err = vio_register_driver(&vnet_driver); return vio_register_driver(&vnet_port_driver);
if (!err) {
err = vio_register_driver(&vnet_port_driver);
if (err)
vio_unregister_driver(&vnet_driver);
}
return err;
} }
static void __exit vnet_exit(void) static void __exit vnet_exit(void)
{ {
vio_unregister_driver(&vnet_port_driver); vio_unregister_driver(&vnet_port_driver);
vio_unregister_driver(&vnet_driver);
} }
module_init(vnet_init); module_init(vnet_init);
......
...@@ -60,11 +60,13 @@ struct vnet { ...@@ -60,11 +60,13 @@ struct vnet {
struct net_device *dev; struct net_device *dev;
u32 msg_enable; u32 msg_enable;
struct vio_dev *vdev;
struct list_head port_list; struct list_head port_list;
struct hlist_head port_hash[VNET_PORT_HASH_SIZE]; struct hlist_head port_hash[VNET_PORT_HASH_SIZE];
struct list_head list;
u64 local_mac;
}; };
#endif /* _SUNVNET_H */ #endif /* _SUNVNET_H */
...@@ -14,11 +14,6 @@ ...@@ -14,11 +14,6 @@
#define __SLOW_DOWN_IO do { } while (0) #define __SLOW_DOWN_IO do { } while (0)
#define SLOW_DOWN_IO do { } while (0) #define SLOW_DOWN_IO do { } while (0)
extern unsigned long virt_to_bus_not_defined_use_pci_map(volatile void *addr);
#define virt_to_bus virt_to_bus_not_defined_use_pci_map
extern unsigned long bus_to_virt_not_defined_use_pci_map(volatile void *addr);
#define bus_to_virt bus_to_virt_not_defined_use_pci_map
/* BIO layer definitions. */ /* BIO layer definitions. */
extern unsigned long kern_base, kern_size; extern unsigned long kern_base, kern_size;
#define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT) #define page_to_phys(page) (page_to_pfn(page) << PAGE_SHIFT)
......
...@@ -61,6 +61,16 @@ extern u64 mdesc_arc_target(struct mdesc_handle *hp, u64 arc); ...@@ -61,6 +61,16 @@ extern u64 mdesc_arc_target(struct mdesc_handle *hp, u64 arc);
extern void mdesc_update(void); extern void mdesc_update(void);
struct mdesc_notifier_client {
void (*add)(struct mdesc_handle *handle, u64 node);
void (*remove)(struct mdesc_handle *handle, u64 node);
const char *node_name;
struct mdesc_notifier_client *next;
};
extern void mdesc_register_notifier(struct mdesc_notifier_client *client);
extern void mdesc_fill_in_cpu_data(cpumask_t mask); extern void mdesc_fill_in_cpu_data(cpumask_t mask);
extern void sun4v_mdesc_init(void); extern void sun4v_mdesc_init(void);
......
...@@ -264,7 +264,7 @@ static inline u32 vio_dring_avail(struct vio_dring_state *dr, ...@@ -264,7 +264,7 @@ static inline u32 vio_dring_avail(struct vio_dring_state *dr,
((dr->prod - dr->cons) & (ring_size - 1))); ((dr->prod - dr->cons) & (ring_size - 1)));
} }
#define VIO_MAX_TYPE_LEN 64 #define VIO_MAX_TYPE_LEN 32
#define VIO_MAX_COMPAT_LEN 64 #define VIO_MAX_COMPAT_LEN 64
struct vio_dev { struct vio_dev {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment