mirror of
https://github.com/joel16/android_kernel_sony_msm8994_rework.git
synced 2024-12-28 06:54:55 +00:00
[SPARC64]: Add proper multicast support to VNET driver.
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
5fc986100c
commit
028ebff269
@ -459,6 +459,22 @@ static int vnet_nack(struct vnet_port *port, void *msgbuf)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int handle_mcast(struct vnet_port *port, void *msgbuf)
|
||||||
|
{
|
||||||
|
struct vio_net_mcast_info *pkt = msgbuf;
|
||||||
|
|
||||||
|
if (pkt->tag.stype != VIO_SUBTYPE_ACK)
|
||||||
|
printk(KERN_ERR PFX "%s: Got unexpected MCAST reply "
|
||||||
|
"[%02x:%02x:%04x:%08x]\n",
|
||||||
|
port->vp->dev->name,
|
||||||
|
pkt->tag.type,
|
||||||
|
pkt->tag.stype,
|
||||||
|
pkt->tag.stype_env,
|
||||||
|
pkt->tag.sid);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void maybe_tx_wakeup(struct vnet *vp)
|
static void maybe_tx_wakeup(struct vnet *vp)
|
||||||
{
|
{
|
||||||
struct net_device *dev = vp->dev;
|
struct net_device *dev = vp->dev;
|
||||||
@ -544,7 +560,10 @@ static void vnet_event(void *arg, int event)
|
|||||||
err = vnet_nack(port, &msgbuf);
|
err = vnet_nack(port, &msgbuf);
|
||||||
}
|
}
|
||||||
} else if (msgbuf.tag.type == VIO_TYPE_CTRL) {
|
} else if (msgbuf.tag.type == VIO_TYPE_CTRL) {
|
||||||
err = vio_control_pkt_engine(vio, &msgbuf);
|
if (msgbuf.tag.stype_env == VNET_MCAST_INFO)
|
||||||
|
err = handle_mcast(port, &msgbuf);
|
||||||
|
else
|
||||||
|
err = vio_control_pkt_engine(vio, &msgbuf);
|
||||||
if (err)
|
if (err)
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
@ -731,9 +750,122 @@ static int vnet_close(struct net_device *dev)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct vnet_mcast_entry *__vnet_mc_find(struct vnet *vp, u8 *addr)
|
||||||
|
{
|
||||||
|
struct vnet_mcast_entry *m;
|
||||||
|
|
||||||
|
for (m = vp->mcast_list; m; m = m->next) {
|
||||||
|
if (!memcmp(m->addr, addr, ETH_ALEN))
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __update_mc_list(struct vnet *vp, struct net_device *dev)
|
||||||
|
{
|
||||||
|
struct dev_addr_list *p;
|
||||||
|
|
||||||
|
for (p = dev->mc_list; p; p = p->next) {
|
||||||
|
struct vnet_mcast_entry *m;
|
||||||
|
|
||||||
|
m = __vnet_mc_find(vp, p->dmi_addr);
|
||||||
|
if (m) {
|
||||||
|
m->hit = 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m) {
|
||||||
|
m = kzalloc(sizeof(*m), GFP_ATOMIC);
|
||||||
|
if (!m)
|
||||||
|
continue;
|
||||||
|
memcpy(m->addr, p->dmi_addr, ETH_ALEN);
|
||||||
|
m->hit = 1;
|
||||||
|
|
||||||
|
m->next = vp->mcast_list;
|
||||||
|
vp->mcast_list = m;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __send_mc_list(struct vnet *vp, struct vnet_port *port)
|
||||||
|
{
|
||||||
|
struct vio_net_mcast_info info;
|
||||||
|
struct vnet_mcast_entry *m, **pp;
|
||||||
|
int n_addrs;
|
||||||
|
|
||||||
|
memset(&info, 0, sizeof(info));
|
||||||
|
|
||||||
|
info.tag.type = VIO_TYPE_CTRL;
|
||||||
|
info.tag.stype = VIO_SUBTYPE_INFO;
|
||||||
|
info.tag.stype_env = VNET_MCAST_INFO;
|
||||||
|
info.tag.sid = vio_send_sid(&port->vio);
|
||||||
|
info.set = 1;
|
||||||
|
|
||||||
|
n_addrs = 0;
|
||||||
|
for (m = vp->mcast_list; m; m = m->next) {
|
||||||
|
if (m->sent)
|
||||||
|
continue;
|
||||||
|
m->sent = 1;
|
||||||
|
memcpy(&info.mcast_addr[n_addrs * ETH_ALEN],
|
||||||
|
m->addr, ETH_ALEN);
|
||||||
|
if (++n_addrs == VNET_NUM_MCAST) {
|
||||||
|
info.count = n_addrs;
|
||||||
|
|
||||||
|
(void) vio_ldc_send(&port->vio, &info,
|
||||||
|
sizeof(info));
|
||||||
|
n_addrs = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (n_addrs) {
|
||||||
|
info.count = n_addrs;
|
||||||
|
(void) vio_ldc_send(&port->vio, &info, sizeof(info));
|
||||||
|
}
|
||||||
|
|
||||||
|
info.set = 0;
|
||||||
|
|
||||||
|
n_addrs = 0;
|
||||||
|
pp = &vp->mcast_list;
|
||||||
|
while ((m = *pp) != NULL) {
|
||||||
|
if (m->hit) {
|
||||||
|
m->hit = 0;
|
||||||
|
pp = &m->next;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(&info.mcast_addr[n_addrs * ETH_ALEN],
|
||||||
|
m->addr, ETH_ALEN);
|
||||||
|
if (++n_addrs == VNET_NUM_MCAST) {
|
||||||
|
info.count = n_addrs;
|
||||||
|
(void) vio_ldc_send(&port->vio, &info,
|
||||||
|
sizeof(info));
|
||||||
|
n_addrs = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pp = m->next;
|
||||||
|
kfree(m);
|
||||||
|
}
|
||||||
|
if (n_addrs) {
|
||||||
|
info.count = n_addrs;
|
||||||
|
(void) vio_ldc_send(&port->vio, &info, sizeof(info));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void vnet_set_rx_mode(struct net_device *dev)
|
static void vnet_set_rx_mode(struct net_device *dev)
|
||||||
{
|
{
|
||||||
/* XXX Implement multicast support XXX */
|
struct vnet *vp = netdev_priv(dev);
|
||||||
|
struct vnet_port *port;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&vp->lock, flags);
|
||||||
|
if (!list_empty(&vp->port_list)) {
|
||||||
|
port = list_entry(vp->port_list.next, struct vnet_port, list);
|
||||||
|
|
||||||
|
if (port->switch_port) {
|
||||||
|
__update_mc_list(vp, dev);
|
||||||
|
__send_mc_list(vp, port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
spin_unlock_irqrestore(&vp->lock, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vnet_change_mtu(struct net_device *dev, int new_mtu)
|
static int vnet_change_mtu(struct net_device *dev, int new_mtu)
|
||||||
@ -1070,6 +1202,7 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev,
|
|||||||
switch_port = 0;
|
switch_port = 0;
|
||||||
if (mdesc_get_property(hp, vdev->mp, "switch-port", NULL) != NULL)
|
if (mdesc_get_property(hp, vdev->mp, "switch-port", NULL) != NULL)
|
||||||
switch_port = 1;
|
switch_port = 1;
|
||||||
|
port->switch_port = switch_port;
|
||||||
|
|
||||||
spin_lock_irqsave(&vp->lock, flags);
|
spin_lock_irqsave(&vp->lock, flags);
|
||||||
if (switch_port)
|
if (switch_port)
|
||||||
|
@ -30,6 +30,8 @@ struct vnet_port {
|
|||||||
|
|
||||||
struct hlist_node hash;
|
struct hlist_node hash;
|
||||||
u8 raddr[ETH_ALEN];
|
u8 raddr[ETH_ALEN];
|
||||||
|
u8 switch_port;
|
||||||
|
u8 __pad;
|
||||||
|
|
||||||
struct vnet *vp;
|
struct vnet *vp;
|
||||||
|
|
||||||
@ -53,6 +55,13 @@ static inline unsigned int vnet_hashfn(u8 *mac)
|
|||||||
return val & (VNET_PORT_HASH_MASK);
|
return val & (VNET_PORT_HASH_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct vnet_mcast_entry {
|
||||||
|
u8 addr[ETH_ALEN];
|
||||||
|
u8 sent;
|
||||||
|
u8 hit;
|
||||||
|
struct vnet_mcast_entry *next;
|
||||||
|
};
|
||||||
|
|
||||||
struct vnet {
|
struct vnet {
|
||||||
/* Protects port_list and port_hash. */
|
/* Protects port_list and port_hash. */
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
@ -65,6 +74,8 @@ struct vnet {
|
|||||||
|
|
||||||
struct hlist_head port_hash[VNET_PORT_HASH_SIZE];
|
struct hlist_head port_hash[VNET_PORT_HASH_SIZE];
|
||||||
|
|
||||||
|
struct vnet_mcast_entry *mcast_list;
|
||||||
|
|
||||||
struct list_head list;
|
struct list_head list;
|
||||||
u64 local_mac;
|
u64 local_mac;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user