mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-02 07:04:24 +00:00
rapidio/rionet: rework to support multiple RIO master ports
Make RIONET driver multi-net safe/capable by introducing per-net lists of RapidIO network peers. Rework registration of network adapters to support all available RIO master port devices. Signed-off-by: Alexandre Bounine <alexandre.bounine@idt.com> Cc: Matt Porter <mporter@kernel.crashing.org> Cc: Li Yang <leoli@freescale.com> Cc: David S. Miller <davem@davemloft.net> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
005842efd1
commit
2fb717ec3e
1 changed files with 70 additions and 63 deletions
|
@ -26,7 +26,7 @@
|
||||||
#include <linux/ethtool.h>
|
#include <linux/ethtool.h>
|
||||||
|
|
||||||
#define DRV_NAME "rionet"
|
#define DRV_NAME "rionet"
|
||||||
#define DRV_VERSION "0.2"
|
#define DRV_VERSION "0.3"
|
||||||
#define DRV_AUTHOR "Matt Porter <mporter@kernel.crashing.org>"
|
#define DRV_AUTHOR "Matt Porter <mporter@kernel.crashing.org>"
|
||||||
#define DRV_DESC "Ethernet over RapidIO"
|
#define DRV_DESC "Ethernet over RapidIO"
|
||||||
|
|
||||||
|
@ -47,8 +47,7 @@ MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
#define RIONET_TX_RING_SIZE CONFIG_RIONET_TX_SIZE
|
#define RIONET_TX_RING_SIZE CONFIG_RIONET_TX_SIZE
|
||||||
#define RIONET_RX_RING_SIZE CONFIG_RIONET_RX_SIZE
|
#define RIONET_RX_RING_SIZE CONFIG_RIONET_RX_SIZE
|
||||||
|
#define RIONET_MAX_NETS 8
|
||||||
static LIST_HEAD(rionet_peers);
|
|
||||||
|
|
||||||
struct rionet_private {
|
struct rionet_private {
|
||||||
struct rio_mport *mport;
|
struct rio_mport *mport;
|
||||||
|
@ -69,17 +68,14 @@ struct rionet_peer {
|
||||||
struct resource *res;
|
struct resource *res;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int rionet_check = 0;
|
struct rionet_net {
|
||||||
static int rionet_capable = 1;
|
struct net_device *ndev;
|
||||||
|
struct list_head peers;
|
||||||
|
struct rio_dev **active;
|
||||||
|
int nact; /* number of active peers */
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
static struct rionet_net nets[RIONET_MAX_NETS];
|
||||||
* This is a fast lookup table for translating TX
|
|
||||||
* Ethernet packets into a destination RIO device. It
|
|
||||||
* could be made into a hash table to save memory depending
|
|
||||||
* on system trade-offs.
|
|
||||||
*/
|
|
||||||
static struct rio_dev **rionet_active;
|
|
||||||
static int nact; /* total number of active rionet peers */
|
|
||||||
|
|
||||||
#define is_rionet_capable(src_ops, dst_ops) \
|
#define is_rionet_capable(src_ops, dst_ops) \
|
||||||
((src_ops & RIO_SRC_OPS_DATA_MSG) && \
|
((src_ops & RIO_SRC_OPS_DATA_MSG) && \
|
||||||
|
@ -185,7 +181,7 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_multicast_ether_addr(eth->h_dest))
|
if (is_multicast_ether_addr(eth->h_dest))
|
||||||
add_num = nact;
|
add_num = nets[rnet->mport->id].nact;
|
||||||
|
|
||||||
if ((rnet->tx_cnt + add_num) > RIONET_TX_RING_SIZE) {
|
if ((rnet->tx_cnt + add_num) > RIONET_TX_RING_SIZE) {
|
||||||
netif_stop_queue(ndev);
|
netif_stop_queue(ndev);
|
||||||
|
@ -197,19 +193,21 @@ static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev)
|
||||||
|
|
||||||
if (is_multicast_ether_addr(eth->h_dest)) {
|
if (is_multicast_ether_addr(eth->h_dest)) {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rnet->mport->sys_size);
|
for (i = 0; i < RIO_MAX_ROUTE_ENTRIES(rnet->mport->sys_size);
|
||||||
i++)
|
i++)
|
||||||
if (rionet_active[i]) {
|
if (nets[rnet->mport->id].active[i]) {
|
||||||
rionet_queue_tx_msg(skb, ndev,
|
rionet_queue_tx_msg(skb, ndev,
|
||||||
rionet_active[i]);
|
nets[rnet->mport->id].active[i]);
|
||||||
if (count)
|
if (count)
|
||||||
atomic_inc(&skb->users);
|
atomic_inc(&skb->users);
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
} else if (RIONET_MAC_MATCH(eth->h_dest)) {
|
} else if (RIONET_MAC_MATCH(eth->h_dest)) {
|
||||||
destid = RIONET_GET_DESTID(eth->h_dest);
|
destid = RIONET_GET_DESTID(eth->h_dest);
|
||||||
if (rionet_active[destid])
|
if (nets[rnet->mport->id].active[destid])
|
||||||
rionet_queue_tx_msg(skb, ndev, rionet_active[destid]);
|
rionet_queue_tx_msg(skb, ndev,
|
||||||
|
nets[rnet->mport->id].active[destid]);
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_unlock_irqrestore(&rnet->tx_lock, flags);
|
spin_unlock_irqrestore(&rnet->tx_lock, flags);
|
||||||
|
@ -228,19 +226,21 @@ static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u
|
||||||
printk(KERN_INFO "%s: doorbell sid %4.4x tid %4.4x info %4.4x",
|
printk(KERN_INFO "%s: doorbell sid %4.4x tid %4.4x info %4.4x",
|
||||||
DRV_NAME, sid, tid, info);
|
DRV_NAME, sid, tid, info);
|
||||||
if (info == RIONET_DOORBELL_JOIN) {
|
if (info == RIONET_DOORBELL_JOIN) {
|
||||||
if (!rionet_active[sid]) {
|
if (!nets[rnet->mport->id].active[sid]) {
|
||||||
list_for_each_entry(peer, &rionet_peers, node) {
|
list_for_each_entry(peer,
|
||||||
|
&nets[rnet->mport->id].peers, node) {
|
||||||
if (peer->rdev->destid == sid) {
|
if (peer->rdev->destid == sid) {
|
||||||
rionet_active[sid] = peer->rdev;
|
nets[rnet->mport->id].active[sid] =
|
||||||
nact++;
|
peer->rdev;
|
||||||
|
nets[rnet->mport->id].nact++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rio_mport_send_doorbell(mport, sid,
|
rio_mport_send_doorbell(mport, sid,
|
||||||
RIONET_DOORBELL_JOIN);
|
RIONET_DOORBELL_JOIN);
|
||||||
}
|
}
|
||||||
} else if (info == RIONET_DOORBELL_LEAVE) {
|
} else if (info == RIONET_DOORBELL_LEAVE) {
|
||||||
rionet_active[sid] = NULL;
|
nets[rnet->mport->id].active[sid] = NULL;
|
||||||
nact--;
|
nets[rnet->mport->id].nact--;
|
||||||
} else {
|
} else {
|
||||||
if (netif_msg_intr(rnet))
|
if (netif_msg_intr(rnet))
|
||||||
printk(KERN_WARNING "%s: unhandled doorbell\n",
|
printk(KERN_WARNING "%s: unhandled doorbell\n",
|
||||||
|
@ -334,7 +334,8 @@ static int rionet_open(struct net_device *ndev)
|
||||||
netif_carrier_on(ndev);
|
netif_carrier_on(ndev);
|
||||||
netif_start_queue(ndev);
|
netif_start_queue(ndev);
|
||||||
|
|
||||||
list_for_each_entry_safe(peer, tmp, &rionet_peers, node) {
|
list_for_each_entry_safe(peer, tmp,
|
||||||
|
&nets[rnet->mport->id].peers, node) {
|
||||||
if (!(peer->res = rio_request_outb_dbell(peer->rdev,
|
if (!(peer->res = rio_request_outb_dbell(peer->rdev,
|
||||||
RIONET_DOORBELL_JOIN,
|
RIONET_DOORBELL_JOIN,
|
||||||
RIONET_DOORBELL_LEAVE)))
|
RIONET_DOORBELL_LEAVE)))
|
||||||
|
@ -359,7 +360,7 @@ static int rionet_close(struct net_device *ndev)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (netif_msg_ifup(rnet))
|
if (netif_msg_ifup(rnet))
|
||||||
printk(KERN_INFO "%s: close\n", DRV_NAME);
|
printk(KERN_INFO "%s: close %s\n", DRV_NAME, ndev->name);
|
||||||
|
|
||||||
netif_stop_queue(ndev);
|
netif_stop_queue(ndev);
|
||||||
netif_carrier_off(ndev);
|
netif_carrier_off(ndev);
|
||||||
|
@ -367,10 +368,11 @@ static int rionet_close(struct net_device *ndev)
|
||||||
for (i = 0; i < RIONET_RX_RING_SIZE; i++)
|
for (i = 0; i < RIONET_RX_RING_SIZE; i++)
|
||||||
kfree_skb(rnet->rx_skb[i]);
|
kfree_skb(rnet->rx_skb[i]);
|
||||||
|
|
||||||
list_for_each_entry_safe(peer, tmp, &rionet_peers, node) {
|
list_for_each_entry_safe(peer, tmp,
|
||||||
if (rionet_active[peer->rdev->destid]) {
|
&nets[rnet->mport->id].peers, node) {
|
||||||
|
if (nets[rnet->mport->id].active[peer->rdev->destid]) {
|
||||||
rio_send_doorbell(peer->rdev, RIONET_DOORBELL_LEAVE);
|
rio_send_doorbell(peer->rdev, RIONET_DOORBELL_LEAVE);
|
||||||
rionet_active[peer->rdev->destid] = NULL;
|
nets[rnet->mport->id].active[peer->rdev->destid] = NULL;
|
||||||
}
|
}
|
||||||
rio_release_outb_dbell(peer->rdev, peer->res);
|
rio_release_outb_dbell(peer->rdev, peer->res);
|
||||||
}
|
}
|
||||||
|
@ -386,17 +388,21 @@ static int rionet_close(struct net_device *ndev)
|
||||||
static void rionet_remove(struct rio_dev *rdev)
|
static void rionet_remove(struct rio_dev *rdev)
|
||||||
{
|
{
|
||||||
struct net_device *ndev = rio_get_drvdata(rdev);
|
struct net_device *ndev = rio_get_drvdata(rdev);
|
||||||
|
unsigned char netid = rdev->net->hport->id;
|
||||||
struct rionet_peer *peer, *tmp;
|
struct rionet_peer *peer, *tmp;
|
||||||
|
|
||||||
free_pages((unsigned long)rionet_active, get_order(sizeof(void *) *
|
|
||||||
RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size)));
|
|
||||||
unregister_netdev(ndev);
|
unregister_netdev(ndev);
|
||||||
free_netdev(ndev);
|
|
||||||
|
|
||||||
list_for_each_entry_safe(peer, tmp, &rionet_peers, node) {
|
free_pages((unsigned long)nets[netid].active, get_order(sizeof(void *) *
|
||||||
|
RIO_MAX_ROUTE_ENTRIES(rdev->net->hport->sys_size)));
|
||||||
|
nets[netid].active = NULL;
|
||||||
|
|
||||||
|
list_for_each_entry_safe(peer, tmp, &nets[netid].peers, node) {
|
||||||
list_del(&peer->node);
|
list_del(&peer->node);
|
||||||
kfree(peer);
|
kfree(peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free_netdev(ndev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void rionet_get_drvinfo(struct net_device *ndev,
|
static void rionet_get_drvinfo(struct net_device *ndev,
|
||||||
|
@ -448,13 +454,13 @@ static int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev)
|
||||||
const size_t rionet_active_bytes = sizeof(void *) *
|
const size_t rionet_active_bytes = sizeof(void *) *
|
||||||
RIO_MAX_ROUTE_ENTRIES(mport->sys_size);
|
RIO_MAX_ROUTE_ENTRIES(mport->sys_size);
|
||||||
|
|
||||||
rionet_active = (struct rio_dev **)__get_free_pages(GFP_KERNEL,
|
nets[mport->id].active = (struct rio_dev **)__get_free_pages(GFP_KERNEL,
|
||||||
get_order(rionet_active_bytes));
|
get_order(rionet_active_bytes));
|
||||||
if (!rionet_active) {
|
if (!nets[mport->id].active) {
|
||||||
rc = -ENOMEM;
|
rc = -ENOMEM;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
memset((void *)rionet_active, 0, rionet_active_bytes);
|
memset((void *)nets[mport->id].active, 0, rionet_active_bytes);
|
||||||
|
|
||||||
/* Set up private area */
|
/* Set up private area */
|
||||||
rnet = netdev_priv(ndev);
|
rnet = netdev_priv(ndev);
|
||||||
|
@ -483,61 +489,62 @@ static int rionet_setup_netdev(struct rio_mport *mport, struct net_device *ndev)
|
||||||
if (rc != 0)
|
if (rc != 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
printk("%s: %s %s Version %s, MAC %pM\n",
|
printk(KERN_INFO "%s: %s %s Version %s, MAC %pM, %s\n",
|
||||||
ndev->name,
|
ndev->name,
|
||||||
DRV_NAME,
|
DRV_NAME,
|
||||||
DRV_DESC,
|
DRV_DESC,
|
||||||
DRV_VERSION,
|
DRV_VERSION,
|
||||||
ndev->dev_addr);
|
ndev->dev_addr,
|
||||||
|
mport->name);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static unsigned long net_table[RIONET_MAX_NETS/sizeof(unsigned long) + 1];
|
||||||
* XXX Make multi-net safe
|
|
||||||
*/
|
|
||||||
static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id)
|
static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id)
|
||||||
{
|
{
|
||||||
int rc = -ENODEV;
|
int rc = -ENODEV;
|
||||||
u32 lsrc_ops, ldst_ops;
|
u32 lsrc_ops, ldst_ops;
|
||||||
struct rionet_peer *peer;
|
struct rionet_peer *peer;
|
||||||
struct net_device *ndev = NULL;
|
struct net_device *ndev = NULL;
|
||||||
|
unsigned char netid = rdev->net->hport->id;
|
||||||
|
int oldnet;
|
||||||
|
|
||||||
/* If local device is not rionet capable, give up quickly */
|
if (netid >= RIONET_MAX_NETS)
|
||||||
if (!rionet_capable)
|
return rc;
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* Allocate our net_device structure */
|
oldnet = test_and_set_bit(netid, net_table);
|
||||||
ndev = alloc_etherdev(sizeof(struct rionet_private));
|
|
||||||
if (ndev == NULL) {
|
|
||||||
rc = -ENOMEM;
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First time through, make sure local device is rionet
|
* First time through, make sure local device is rionet
|
||||||
* capable, setup netdev, and set flags so this is skipped
|
* capable, setup netdev (will be skipped on later probes)
|
||||||
* on later probes
|
|
||||||
*/
|
*/
|
||||||
if (!rionet_check) {
|
if (!oldnet) {
|
||||||
rio_local_read_config_32(rdev->net->hport, RIO_SRC_OPS_CAR,
|
rio_local_read_config_32(rdev->net->hport, RIO_SRC_OPS_CAR,
|
||||||
&lsrc_ops);
|
&lsrc_ops);
|
||||||
rio_local_read_config_32(rdev->net->hport, RIO_DST_OPS_CAR,
|
rio_local_read_config_32(rdev->net->hport, RIO_DST_OPS_CAR,
|
||||||
&ldst_ops);
|
&ldst_ops);
|
||||||
if (!is_rionet_capable(lsrc_ops, ldst_ops)) {
|
if (!is_rionet_capable(lsrc_ops, ldst_ops)) {
|
||||||
printk(KERN_ERR
|
printk(KERN_ERR
|
||||||
"%s: local device is not network capable\n",
|
"%s: local device %s is not network capable\n",
|
||||||
DRV_NAME);
|
DRV_NAME, rdev->net->hport->name);
|
||||||
rionet_check = 1;
|
|
||||||
rionet_capable = 0;
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Allocate our net_device structure */
|
||||||
|
ndev = alloc_etherdev(sizeof(struct rionet_private));
|
||||||
|
if (ndev == NULL) {
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
nets[netid].ndev = ndev;
|
||||||
rc = rionet_setup_netdev(rdev->net->hport, ndev);
|
rc = rionet_setup_netdev(rdev->net->hport, ndev);
|
||||||
rionet_check = 1;
|
INIT_LIST_HEAD(&nets[netid].peers);
|
||||||
nact = 0;
|
nets[netid].nact = 0;
|
||||||
}
|
} else if (nets[netid].ndev == NULL)
|
||||||
|
goto out;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the remote device has mailbox/doorbell capabilities,
|
* If the remote device has mailbox/doorbell capabilities,
|
||||||
|
@ -549,10 +556,10 @@ static int rionet_probe(struct rio_dev *rdev, const struct rio_device_id *id)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
peer->rdev = rdev;
|
peer->rdev = rdev;
|
||||||
list_add_tail(&peer->node, &rionet_peers);
|
list_add_tail(&peer->node, &nets[netid].peers);
|
||||||
}
|
}
|
||||||
|
|
||||||
rio_set_drvdata(rdev, ndev);
|
rio_set_drvdata(rdev, nets[netid].ndev);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return rc;
|
return rc;
|
||||||
|
|
Loading…
Reference in a new issue