Commit 2fb717ec authored by Alexandre Bounine's avatar Alexandre Bounine Committed by Linus Torvalds

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: default avatarAlexandre 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: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 005842ef
...@@ -26,7 +26,7 @@ ...@@ -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"); ...@@ -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 { ...@@ -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) ...@@ -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) ...@@ -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 ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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;
......
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