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.
This commit is contained in:
commit
31bdc5dc76
|
@ -21,6 +21,9 @@ config GENERIC_ISA_DMA
|
|||
bool
|
||||
default y
|
||||
|
||||
config ARCH_NO_VIRT_TO_BUS
|
||||
def_bool y
|
||||
|
||||
source "init/Kconfig"
|
||||
|
||||
menu "General machine setup"
|
||||
|
|
|
@ -62,6 +62,9 @@ config AUDIT_ARCH
|
|||
bool
|
||||
default y
|
||||
|
||||
config ARCH_NO_VIRT_TO_BUS
|
||||
def_bool y
|
||||
|
||||
choice
|
||||
prompt "Kernel page size"
|
||||
default SPARC64_PAGE_SIZE_8KB
|
||||
|
|
|
@ -1013,6 +1013,19 @@ static void ds_up(struct ds_info *dp)
|
|||
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)
|
||||
{
|
||||
struct ds_info *dp = arg;
|
||||
|
@ -1028,6 +1041,12 @@ static void ds_event(void *arg, int event)
|
|||
return;
|
||||
}
|
||||
|
||||
if (event == LDC_EVENT_RESET) {
|
||||
ds_reset(dp);
|
||||
spin_unlock_irqrestore(&ds_lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
if (event != LDC_EVENT_DATA_READY) {
|
||||
printk(KERN_WARNING PFX "Unexpected LDC event %d\n", event);
|
||||
spin_unlock_irqrestore(&ds_lock, flags);
|
||||
|
|
|
@ -137,7 +137,7 @@ static struct mdesc_handle *mdesc_kmalloc(unsigned int mdesc_size)
|
|||
sizeof(struct mdesc_hdr) +
|
||||
mdesc_size);
|
||||
|
||||
base = kmalloc(handle_size + 15, GFP_KERNEL);
|
||||
base = kmalloc(handle_size + 15, GFP_KERNEL | __GFP_NOFAIL);
|
||||
if (base) {
|
||||
struct mdesc_handle *hp;
|
||||
unsigned long addr;
|
||||
|
@ -214,18 +214,83 @@ void mdesc_release(struct mdesc_handle *hp)
|
|||
}
|
||||
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)
|
||||
{
|
||||
unsigned long len, real_len, status;
|
||||
struct mdesc_handle *hp, *orig_hp;
|
||||
unsigned long flags;
|
||||
|
||||
mutex_lock(&mdesc_mutex);
|
||||
|
||||
(void) sun4v_mach_desc(0UL, 0UL, &len);
|
||||
|
||||
hp = mdesc_alloc(len, &kmalloc_mdesc_memops);
|
||||
if (!hp) {
|
||||
printk(KERN_ERR "MD: mdesc alloc fails\n");
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
status = sun4v_mach_desc(__pa(&hp->mdesc), len, &real_len);
|
||||
|
@ -234,18 +299,25 @@ void mdesc_update(void)
|
|||
status);
|
||||
atomic_dec(&hp->refcnt);
|
||||
mdesc_free(hp);
|
||||
return;
|
||||
goto out;
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&mdesc_lock, flags);
|
||||
orig_hp = cur_mdesc;
|
||||
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))
|
||||
mdesc_free(orig_hp);
|
||||
else
|
||||
list_add(&orig_hp->list, &mdesc_zombie_list);
|
||||
spin_unlock_irqrestore(&mdesc_lock, flags);
|
||||
|
||||
out:
|
||||
mutex_unlock(&mdesc_mutex);
|
||||
}
|
||||
|
||||
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,
|
|||
static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
|
||||
struct device *parent)
|
||||
{
|
||||
const char *type, *compat;
|
||||
const char *type, *compat, *bus_id_name;
|
||||
struct device_node *dp;
|
||||
struct vio_dev *vdev;
|
||||
int err, tlen, clen;
|
||||
const u64 *id;
|
||||
|
||||
type = mdesc_get_property(hp, mp, "device-type", &tlen);
|
||||
if (!type) {
|
||||
|
@ -220,6 +221,16 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
|
|||
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);
|
||||
if (!compat) {
|
||||
clen = 0;
|
||||
|
@ -249,7 +260,14 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
|
|||
|
||||
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.bus = &vio_bus_type;
|
||||
vdev->dev.release = vio_dev_release;
|
||||
|
@ -269,6 +287,8 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
|
|||
}
|
||||
vdev->dp = dp;
|
||||
|
||||
printk(KERN_ERR "VIO: Adding device %s\n", vdev->dev.bus_id);
|
||||
|
||||
err = device_register(&vdev->dev);
|
||||
if (err) {
|
||||
printk(KERN_ERR "VIO: Could not register device %s, err=%d\n",
|
||||
|
@ -283,45 +303,45 @@ static struct vio_dev *vio_create_one(struct mdesc_handle *hp, u64 mp,
|
|||
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;
|
||||
static int vio_md_node_match(struct device *dev, void *arg)
|
||||
{
|
||||
struct vio_dev *vdev = to_vio_dev(dev);
|
||||
|
||||
target = mdesc_arc_target(hp, a);
|
||||
vdev = vio_create_one(hp, target, &parent->dev);
|
||||
if (vdev)
|
||||
walk_tree(hp, target, vdev);
|
||||
if (vdev->mp == (u64) arg)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vio_remove(struct mdesc_handle *hp, u64 node)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
dev = device_find_child(&root_vdev->dev, (void *) node,
|
||||
vio_md_node_match);
|
||||
if (dev) {
|
||||
printk(KERN_INFO "VIO: Removing device %s\n", dev->bus_id);
|
||||
|
||||
device_unregister(dev);
|
||||
}
|
||||
}
|
||||
|
||||
static void create_devices(struct mdesc_handle *hp, u64 root)
|
||||
{
|
||||
u64 mp;
|
||||
static struct mdesc_notifier_client vio_device_notifier = {
|
||||
.add = vio_add,
|
||||
.remove = vio_remove,
|
||||
.node_name = "virtual-device-port",
|
||||
};
|
||||
|
||||
root_vdev = vio_create_one(hp, root, NULL);
|
||||
if (!root_vdev) {
|
||||
printk(KERN_ERR "VIO: Coult not create root device.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
walk_tree(hp, root, root_vdev);
|
||||
|
||||
/* Domain services is odd as it doesn't sit underneath the
|
||||
* channel-devices node, so we plug it in manually.
|
||||
*/
|
||||
mp = mdesc_node_by_name(hp, MDESC_NODE_NULL, "domain-services");
|
||||
if (mp != MDESC_NODE_NULL) {
|
||||
struct vio_dev *parent = vio_create_one(hp, mp,
|
||||
&root_vdev->dev);
|
||||
|
||||
if (parent)
|
||||
walk_tree(hp, mp, parent);
|
||||
}
|
||||
}
|
||||
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_compat = "SUNW,sun4v-channel-devices";
|
||||
|
@ -381,11 +401,19 @@ static int __init vio_init(void)
|
|||
|
||||
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);
|
||||
|
||||
return 0;
|
||||
return err;
|
||||
|
||||
out_release:
|
||||
mdesc_release(hp);
|
||||
|
|
|
@ -78,6 +78,24 @@ static int start_handshake(struct vio_driver_state *vio)
|
|||
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)
|
||||
{
|
||||
if (event == LDC_EVENT_UP) {
|
||||
|
@ -98,6 +116,16 @@ void vio_link_state_change(struct vio_driver_state *vio, int event)
|
|||
break;
|
||||
}
|
||||
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);
|
||||
|
@ -396,6 +424,8 @@ static int process_dreg_info(struct vio_driver_state *vio,
|
|||
if (vio->dr_state & VIO_DR_STATE_RXREG)
|
||||
goto send_nack;
|
||||
|
||||
BUG_ON(vio->desc_buf);
|
||||
|
||||
vio->desc_buf = kzalloc(pkt->descr_size, GFP_ATOMIC);
|
||||
if (!vio->desc_buf)
|
||||
goto send_nack;
|
||||
|
|
|
@ -45,8 +45,6 @@ struct vdc_req_entry {
|
|||
struct vdc_port {
|
||||
struct vio_driver_state vio;
|
||||
|
||||
struct vdc *vp;
|
||||
|
||||
struct gendisk *disk;
|
||||
|
||||
struct vdc_completion *cmp;
|
||||
|
@ -72,8 +70,6 @@ struct vdc_port {
|
|||
|
||||
struct vio_disk_geom geom;
|
||||
struct vio_disk_vtoc label;
|
||||
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
struct vdc {
|
||||
/* Protects prot_list. */
|
||||
spinlock_t lock;
|
||||
|
||||
struct vio_dev *dev;
|
||||
|
||||
struct list_head port_list;
|
||||
};
|
||||
|
||||
/* Ordered from largest major to lowest */
|
||||
static struct vio_version vdc_versions[] = {
|
||||
{ .major = 1, .minor = 0 },
|
||||
|
@ -747,21 +734,23 @@ static struct vio_driver_ops vdc_vio_ops = {
|
|||
.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,
|
||||
const struct vio_device_id *id)
|
||||
{
|
||||
struct mdesc_handle *hp;
|
||||
struct vdc_port *port;
|
||||
unsigned long flags;
|
||||
struct vdc *vp;
|
||||
const u64 *port_id;
|
||||
int err;
|
||||
|
||||
vp = dev_get_drvdata(vdev->dev.parent);
|
||||
if (!vp) {
|
||||
printk(KERN_ERR PFX "Cannot find port parent vdc.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
print_version();
|
||||
|
||||
hp = mdesc_grab();
|
||||
|
||||
|
@ -783,7 +772,6 @@ static int __devinit vdc_port_probe(struct vio_dev *vdev,
|
|||
goto err_out_release_mdesc;
|
||||
}
|
||||
|
||||
port->vp = vp;
|
||||
port->dev_no = *port_id;
|
||||
|
||||
if (port->dev_no >= 26)
|
||||
|
@ -818,12 +806,6 @@ static int __devinit vdc_port_probe(struct vio_dev *vdev,
|
|||
if (err)
|
||||
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);
|
||||
|
||||
mdesc_release(hp);
|
||||
|
@ -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)
|
||||
{
|
||||
int err;
|
||||
|
@ -940,19 +870,13 @@ static int __init vdc_init(void)
|
|||
goto out_err;
|
||||
|
||||
vdc_major = err;
|
||||
err = vio_register_driver(&vdc_driver);
|
||||
if (err)
|
||||
goto out_unregister_blkdev;
|
||||
|
||||
err = vio_register_driver(&vdc_port_driver);
|
||||
if (err)
|
||||
goto out_unregister_vdc;
|
||||
goto out_unregister_blkdev;
|
||||
|
||||
return 0;
|
||||
|
||||
out_unregister_vdc:
|
||||
vio_unregister_driver(&vdc_driver);
|
||||
|
||||
out_unregister_blkdev:
|
||||
unregister_blkdev(vdc_major, VDCBLK_NAME);
|
||||
vdc_major = 0;
|
||||
|
@ -964,7 +888,6 @@ out_err:
|
|||
static void __exit vdc_exit(void)
|
||||
{
|
||||
vio_unregister_driver(&vdc_port_driver);
|
||||
vio_unregister_driver(&vdc_driver);
|
||||
unregister_blkdev(vdc_major, VDCBLK_NAME);
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/netdevice.h>
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <asm/vio.h>
|
||||
#include <asm/ldc.h>
|
||||
|
@ -497,6 +498,8 @@ static void vnet_event(void *arg, int event)
|
|||
vio_link_state_change(vio, event);
|
||||
spin_unlock_irqrestore(&vio->lock, flags);
|
||||
|
||||
if (event == LDC_EVENT_RESET)
|
||||
vio_port_up(vio);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -875,6 +878,115 @@ err_out:
|
|||
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 = {
|
||||
.event = vnet_event,
|
||||
.mtu = 64,
|
||||
|
@ -887,6 +999,14 @@ static struct vio_driver_ops vnet_vio_ops = {
|
|||
.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";
|
||||
|
||||
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;
|
||||
int len, i, err, switch_port;
|
||||
|
||||
vp = dev_get_drvdata(vdev->dev.parent);
|
||||
if (!vp) {
|
||||
printk(KERN_ERR PFX "Cannot find port parent vnet.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
print_version();
|
||||
|
||||
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);
|
||||
err = -ENODEV;
|
||||
if (!rmac) {
|
||||
|
@ -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)
|
||||
{
|
||||
int err = vio_register_driver(&vnet_driver);
|
||||
|
||||
if (!err) {
|
||||
err = vio_register_driver(&vnet_port_driver);
|
||||
if (err)
|
||||
vio_unregister_driver(&vnet_driver);
|
||||
}
|
||||
|
||||
return err;
|
||||
return vio_register_driver(&vnet_port_driver);
|
||||
}
|
||||
|
||||
static void __exit vnet_exit(void)
|
||||
{
|
||||
vio_unregister_driver(&vnet_port_driver);
|
||||
vio_unregister_driver(&vnet_driver);
|
||||
}
|
||||
|
||||
module_init(vnet_init);
|
||||
|
|
|
@ -60,11 +60,13 @@ struct vnet {
|
|||
struct net_device *dev;
|
||||
|
||||
u32 msg_enable;
|
||||
struct vio_dev *vdev;
|
||||
|
||||
struct list_head port_list;
|
||||
|
||||
struct hlist_head port_hash[VNET_PORT_HASH_SIZE];
|
||||
|
||||
struct list_head list;
|
||||
u64 local_mac;
|
||||
};
|
||||
|
||||
#endif /* _SUNVNET_H */
|
||||
|
|
|
@ -14,11 +14,6 @@
|
|||
#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. */
|
||||
extern unsigned long kern_base, kern_size;
|
||||
#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);
|
|||
|
||||
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 sun4v_mdesc_init(void);
|
||||
|
|
|
@ -264,7 +264,7 @@ static inline u32 vio_dring_avail(struct vio_dring_state *dr,
|
|||
((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
|
||||
|
||||
struct vio_dev {
|
||||
|
|
Loading…
Reference in New Issue