Commit e6b585ca authored by Alexandre Bounine's avatar Alexandre Bounine Committed by Linus Torvalds

rapidio: move net allocation into core code

Make net allocation/release routines available to all components of
RapidIO subsystem by moving code from rio-scan enumerator.

Make destination ID allocation method private to existing enumerator
because other enumeration methods can use their own algorithm.

Setup net device object as a parent of all RapidIO devices residing in
it and register net as a child of active mport device.
Signed-off-by: default avatarAlexandre Bounine <alexandre.bounine@idt.com>
Cc: Matt Porter <mporter@kernel.crashing.org>
Cc: Aurelien Jacquiot <a-jacquiot@ti.com>
Cc: Andre van Herk <andre.van.herk@prodrive-technologies.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent b74ec56e
...@@ -39,6 +39,13 @@ ...@@ -39,6 +39,13 @@
static void rio_init_em(struct rio_dev *rdev); static void rio_init_em(struct rio_dev *rdev);
struct rio_id_table {
u16 start; /* logical minimal id */
u32 max; /* max number of IDs in table */
spinlock_t lock;
unsigned long table[0];
};
static int next_destid = 0; static int next_destid = 0;
static int next_comptag = 1; static int next_comptag = 1;
...@@ -62,7 +69,7 @@ static int rio_mport_phys_table[] = { ...@@ -62,7 +69,7 @@ static int rio_mport_phys_table[] = {
static u16 rio_destid_alloc(struct rio_net *net) static u16 rio_destid_alloc(struct rio_net *net)
{ {
int destid; int destid;
struct rio_id_table *idtab = &net->destid_table; struct rio_id_table *idtab = (struct rio_id_table *)net->enum_data;
spin_lock(&idtab->lock); spin_lock(&idtab->lock);
destid = find_first_zero_bit(idtab->table, idtab->max); destid = find_first_zero_bit(idtab->table, idtab->max);
...@@ -88,7 +95,7 @@ static u16 rio_destid_alloc(struct rio_net *net) ...@@ -88,7 +95,7 @@ static u16 rio_destid_alloc(struct rio_net *net)
static int rio_destid_reserve(struct rio_net *net, u16 destid) static int rio_destid_reserve(struct rio_net *net, u16 destid)
{ {
int oldbit; int oldbit;
struct rio_id_table *idtab = &net->destid_table; struct rio_id_table *idtab = (struct rio_id_table *)net->enum_data;
destid -= idtab->start; destid -= idtab->start;
spin_lock(&idtab->lock); spin_lock(&idtab->lock);
...@@ -106,7 +113,7 @@ static int rio_destid_reserve(struct rio_net *net, u16 destid) ...@@ -106,7 +113,7 @@ static int rio_destid_reserve(struct rio_net *net, u16 destid)
*/ */
static void rio_destid_free(struct rio_net *net, u16 destid) static void rio_destid_free(struct rio_net *net, u16 destid)
{ {
struct rio_id_table *idtab = &net->destid_table; struct rio_id_table *idtab = (struct rio_id_table *)net->enum_data;
destid -= idtab->start; destid -= idtab->start;
spin_lock(&idtab->lock); spin_lock(&idtab->lock);
...@@ -121,7 +128,7 @@ static void rio_destid_free(struct rio_net *net, u16 destid) ...@@ -121,7 +128,7 @@ static void rio_destid_free(struct rio_net *net, u16 destid)
static u16 rio_destid_first(struct rio_net *net) static u16 rio_destid_first(struct rio_net *net)
{ {
int destid; int destid;
struct rio_id_table *idtab = &net->destid_table; struct rio_id_table *idtab = (struct rio_id_table *)net->enum_data;
spin_lock(&idtab->lock); spin_lock(&idtab->lock);
destid = find_first_bit(idtab->table, idtab->max); destid = find_first_bit(idtab->table, idtab->max);
...@@ -141,7 +148,7 @@ static u16 rio_destid_first(struct rio_net *net) ...@@ -141,7 +148,7 @@ static u16 rio_destid_first(struct rio_net *net)
static u16 rio_destid_next(struct rio_net *net, u16 from) static u16 rio_destid_next(struct rio_net *net, u16 from)
{ {
int destid; int destid;
struct rio_id_table *idtab = &net->destid_table; struct rio_id_table *idtab = (struct rio_id_table *)net->enum_data;
spin_lock(&idtab->lock); spin_lock(&idtab->lock);
destid = find_next_bit(idtab->table, idtab->max, from); destid = find_next_bit(idtab->table, idtab->max, from);
...@@ -458,7 +465,7 @@ static struct rio_dev *rio_setup_device(struct rio_net *net, ...@@ -458,7 +465,7 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
rdev->comp_tag & RIO_CTAG_UDEVID); rdev->comp_tag & RIO_CTAG_UDEVID);
} }
rdev->dev.parent = &port->dev; rdev->dev.parent = &net->dev;
rio_attach_device(rdev); rio_attach_device(rdev);
rdev->dev.release = rio_release_dev; rdev->dev.release = rio_release_dev;
rdev->dma_mask = DMA_BIT_MASK(32); rdev->dma_mask = DMA_BIT_MASK(32);
...@@ -855,50 +862,71 @@ static int rio_mport_is_active(struct rio_mport *port) ...@@ -855,50 +862,71 @@ static int rio_mport_is_active(struct rio_mport *port)
return result & RIO_PORT_N_ERR_STS_PORT_OK; return result & RIO_PORT_N_ERR_STS_PORT_OK;
} }
/** static void rio_scan_release_net(struct rio_net *net)
* rio_alloc_net- Allocate and configure a new RIO network {
* @port: Master port associated with the RIO network pr_debug("RIO-SCAN: %s: net_%d\n", __func__, net->id);
kfree(net->enum_data);
}
static void rio_scan_release_dev(struct device *dev)
{
struct rio_net *net;
net = to_rio_net(dev);
pr_debug("RIO-SCAN: %s: net_%d\n", __func__, net->id);
kfree(net);
}
/*
* rio_scan_alloc_net - Allocate and configure a new RIO network
* @mport: Master port associated with the RIO network
* @do_enum: Enumeration/Discovery mode flag * @do_enum: Enumeration/Discovery mode flag
* @start: logical minimal start id for new net * @start: logical minimal start id for new net
* *
* Allocates a RIO network structure, initializes per-network * Allocates a new RIO network structure and initializes enumerator-specific
* list heads, and adds the associated master port to the * part of it (if required).
* network list of associated master ports. Returns a * Returns a RIO network pointer on success or %NULL on failure.
* RIO network pointer on success or %NULL on failure.
*/ */
static struct rio_net *rio_alloc_net(struct rio_mport *port, static struct rio_net *rio_scan_alloc_net(struct rio_mport *mport,
int do_enum, u16 start) int do_enum, u16 start)
{ {
struct rio_net *net; struct rio_net *net;
net = kzalloc(sizeof(struct rio_net), GFP_KERNEL); net = rio_alloc_net(mport);
if (net && do_enum) { if (net && do_enum) {
net->destid_table.table = kcalloc( struct rio_id_table *idtab;
BITS_TO_LONGS(RIO_MAX_ROUTE_ENTRIES(port->sys_size)), size_t size;
sizeof(long),
GFP_KERNEL); size = sizeof(struct rio_id_table) +
BITS_TO_LONGS(
RIO_MAX_ROUTE_ENTRIES(mport->sys_size)
) * sizeof(long);
if (net->destid_table.table == NULL) { idtab = kzalloc(size, GFP_KERNEL);
if (idtab == NULL) {
pr_err("RIO: failed to allocate destID table\n"); pr_err("RIO: failed to allocate destID table\n");
kfree(net); rio_free_net(net);
net = NULL; net = NULL;
} else { } else {
net->destid_table.start = start; net->enum_data = idtab;
net->destid_table.max = net->release = rio_scan_release_net;
RIO_MAX_ROUTE_ENTRIES(port->sys_size); idtab->start = start;
spin_lock_init(&net->destid_table.lock); idtab->max = RIO_MAX_ROUTE_ENTRIES(mport->sys_size);
spin_lock_init(&idtab->lock);
} }
} }
if (net) { if (net) {
INIT_LIST_HEAD(&net->node); net->id = mport->id;
INIT_LIST_HEAD(&net->devices); net->hport = mport;
INIT_LIST_HEAD(&net->switches); dev_set_name(&net->dev, "rnet_%d", net->id);
INIT_LIST_HEAD(&net->mports); net->dev.parent = &mport->dev;
list_add_tail(&port->nnode, &net->mports); net->dev.release = rio_scan_release_dev;
net->hport = port; rio_add_net(net);
net->id = port->id;
} }
return net; return net;
} }
...@@ -1007,7 +1035,7 @@ static int rio_enum_mport(struct rio_mport *mport, u32 flags) ...@@ -1007,7 +1035,7 @@ static int rio_enum_mport(struct rio_mport *mport, u32 flags)
/* If master port has an active link, allocate net and enum peers */ /* If master port has an active link, allocate net and enum peers */
if (rio_mport_is_active(mport)) { if (rio_mport_is_active(mport)) {
net = rio_alloc_net(mport, 1, 0); net = rio_scan_alloc_net(mport, 1, 0);
if (!net) { if (!net) {
printk(KERN_ERR "RIO: failed to allocate new net\n"); printk(KERN_ERR "RIO: failed to allocate new net\n");
rc = -ENOMEM; rc = -ENOMEM;
...@@ -1124,7 +1152,7 @@ static int rio_disc_mport(struct rio_mport *mport, u32 flags) ...@@ -1124,7 +1152,7 @@ static int rio_disc_mport(struct rio_mport *mport, u32 flags)
enum_done: enum_done:
pr_debug("RIO: ... enumeration done\n"); pr_debug("RIO: ... enumeration done\n");
net = rio_alloc_net(mport, 0, 0); net = rio_scan_alloc_net(mport, 0, 0);
if (!net) { if (!net) {
printk(KERN_ERR "RIO: Failed to allocate new net\n"); printk(KERN_ERR "RIO: Failed to allocate new net\n");
goto bail; goto bail;
......
...@@ -42,6 +42,7 @@ MODULE_PARM_DESC(hdid, ...@@ -42,6 +42,7 @@ MODULE_PARM_DESC(hdid,
"Destination ID assignment to local RapidIO controllers"); "Destination ID assignment to local RapidIO controllers");
static LIST_HEAD(rio_devices); static LIST_HEAD(rio_devices);
static LIST_HEAD(rio_nets);
static DEFINE_SPINLOCK(rio_global_list_lock); static DEFINE_SPINLOCK(rio_global_list_lock);
static LIST_HEAD(rio_mports); static LIST_HEAD(rio_mports);
...@@ -84,6 +85,58 @@ int rio_query_mport(struct rio_mport *port, ...@@ -84,6 +85,58 @@ int rio_query_mport(struct rio_mport *port,
} }
EXPORT_SYMBOL(rio_query_mport); EXPORT_SYMBOL(rio_query_mport);
/**
* rio_alloc_net- Allocate and initialize a new RIO network data structure
* @mport: Master port associated with the RIO network
*
* Allocates a RIO network structure, initializes per-network
* list heads, and adds the associated master port to the
* network list of associated master ports. Returns a
* RIO network pointer on success or %NULL on failure.
*/
struct rio_net *rio_alloc_net(struct rio_mport *mport)
{
struct rio_net *net;
net = kzalloc(sizeof(struct rio_net), GFP_KERNEL);
if (net) {
INIT_LIST_HEAD(&net->node);
INIT_LIST_HEAD(&net->devices);
INIT_LIST_HEAD(&net->switches);
INIT_LIST_HEAD(&net->mports);
mport->net = net;
}
return net;
}
EXPORT_SYMBOL_GPL(rio_alloc_net);
int rio_add_net(struct rio_net *net)
{
int err;
err = device_register(&net->dev);
if (err)
return err;
spin_lock(&rio_global_list_lock);
list_add_tail(&net->node, &rio_nets);
spin_unlock(&rio_global_list_lock);
return 0;
}
EXPORT_SYMBOL_GPL(rio_add_net);
void rio_free_net(struct rio_net *net)
{
spin_lock(&rio_global_list_lock);
if (!list_empty(&net->node))
list_del(&net->node);
spin_unlock(&rio_global_list_lock);
if (net->release)
net->release(net);
device_unregister(&net->dev);
}
EXPORT_SYMBOL_GPL(rio_free_net);
/** /**
* rio_add_device- Adds a RIO device to the device model * rio_add_device- Adds a RIO device to the device model
* @rdev: RIO device * @rdev: RIO device
......
...@@ -39,6 +39,9 @@ extern int rio_route_get_entry(struct rio_dev *rdev, u16 table, ...@@ -39,6 +39,9 @@ extern int rio_route_get_entry(struct rio_dev *rdev, u16 table,
extern int rio_route_clr_table(struct rio_dev *rdev, u16 table, int lock); extern int rio_route_clr_table(struct rio_dev *rdev, u16 table, int lock);
extern int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock); extern int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock);
extern struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from); extern struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from);
extern struct rio_net *rio_alloc_net(struct rio_mport *mport);
extern int rio_add_net(struct rio_net *net);
extern void rio_free_net(struct rio_net *net);
extern int rio_add_device(struct rio_dev *rdev); extern int rio_add_device(struct rio_dev *rdev);
extern void rio_del_device(struct rio_dev *rdev); extern void rio_del_device(struct rio_dev *rdev);
extern int rio_enable_rx_tx_port(struct rio_mport *port, int local, u16 destid, extern int rio_enable_rx_tx_port(struct rio_mport *port, int local, u16 destid,
......
...@@ -202,6 +202,7 @@ struct rio_dev { ...@@ -202,6 +202,7 @@ struct rio_dev {
#define to_rio_dev(n) container_of(n, struct rio_dev, dev) #define to_rio_dev(n) container_of(n, struct rio_dev, dev)
#define sw_to_rio_dev(n) container_of(n, struct rio_dev, rswitch[0]) #define sw_to_rio_dev(n) container_of(n, struct rio_dev, rswitch[0])
#define to_rio_mport(n) container_of(n, struct rio_mport, dev) #define to_rio_mport(n) container_of(n, struct rio_mport, dev)
#define to_rio_net(n) container_of(n, struct rio_net, dev)
/** /**
* struct rio_msg - RIO message event * struct rio_msg - RIO message event
...@@ -237,6 +238,7 @@ enum rio_phy_type { ...@@ -237,6 +238,7 @@ enum rio_phy_type {
* @dbells: List of doorbell events * @dbells: List of doorbell events
* @node: Node in global list of master ports * @node: Node in global list of master ports
* @nnode: Node in network list of master ports * @nnode: Node in network list of master ports
* @net: RIO net this mport is attached to
* @iores: I/O mem resource that this master port interface owns * @iores: I/O mem resource that this master port interface owns
* @riores: RIO resources that this master port interfaces owns * @riores: RIO resources that this master port interfaces owns
* @inb_msg: RIO inbound message event descriptors * @inb_msg: RIO inbound message event descriptors
...@@ -258,6 +260,7 @@ struct rio_mport { ...@@ -258,6 +260,7 @@ struct rio_mport {
struct list_head dbells; /* list of doorbell events */ struct list_head dbells; /* list of doorbell events */
struct list_head node; /* node in global list of ports */ struct list_head node; /* node in global list of ports */
struct list_head nnode; /* node in net list of ports */ struct list_head nnode; /* node in net list of ports */
struct rio_net *net; /* RIO net this mport is attached to */
struct resource iores; struct resource iores;
struct resource riores[RIO_MAX_MPORT_RESOURCES]; struct resource riores[RIO_MAX_MPORT_RESOURCES];
struct rio_msg inb_msg[RIO_MAX_MBOX]; struct rio_msg inb_msg[RIO_MAX_MBOX];
...@@ -287,13 +290,6 @@ struct rio_mport { ...@@ -287,13 +290,6 @@ struct rio_mport {
*/ */
#define RIO_SCAN_ENUM_NO_WAIT 0x00000001 /* Do not wait for enum completed */ #define RIO_SCAN_ENUM_NO_WAIT 0x00000001 /* Do not wait for enum completed */
struct rio_id_table {
u16 start; /* logical minimal id */
u32 max; /* max number of IDs in table */
spinlock_t lock;
unsigned long *table;
};
/** /**
* struct rio_net - RIO network info * struct rio_net - RIO network info
* @node: Node in global list of RIO networks * @node: Node in global list of RIO networks
...@@ -302,7 +298,9 @@ struct rio_id_table { ...@@ -302,7 +298,9 @@ struct rio_id_table {
* @mports: List of master ports accessing this network * @mports: List of master ports accessing this network
* @hport: Default port for accessing this network * @hport: Default port for accessing this network
* @id: RIO network ID * @id: RIO network ID
* @destid_table: destID allocation table * @dev: Device object
* @enum_data: private data specific to a network enumerator
* @release: enumerator-specific release callback
*/ */
struct rio_net { struct rio_net {
struct list_head node; /* node in list of networks */ struct list_head node; /* node in list of networks */
...@@ -311,7 +309,9 @@ struct rio_net { ...@@ -311,7 +309,9 @@ struct rio_net {
struct list_head mports; /* list of ports accessing net */ struct list_head mports; /* list of ports accessing net */
struct rio_mport *hport; /* primary port for accessing net */ struct rio_mport *hport; /* primary port for accessing net */
unsigned char id; /* RIO network ID */ unsigned char id; /* RIO network ID */
struct rio_id_table destid_table; /* destID allocation table */ struct device dev;
void *enum_data; /* private data for enumerator of the network */
void (*release)(struct rio_net *net);
}; };
enum rio_link_speed { enum rio_link_speed {
......
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