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_comptag = 1;
static u16 rio_destid_alloc(struct rio_net *net)
{
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);
destid = find_first_zero_bit(idtab->table, idtab->max);
static int rio_destid_reserve(struct rio_net *net, u16 destid)
{
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;
spin_lock(&idtab->lock);
*/
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;
spin_lock(&idtab->lock);
static u16 rio_destid_first(struct rio_net *net)
{
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);
destid = find_first_bit(idtab->table, idtab->max);
static u16 rio_destid_next(struct rio_net *net, u16 from)
{
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);
destid = find_next_bit(idtab->table, idtab->max, from);
rdev->comp_tag & RIO_CTAG_UDEVID);
}
- rdev->dev.parent = &port->dev;
+ rdev->dev.parent = &net->dev;
rio_attach_device(rdev);
rdev->dev.release = rio_release_dev;
rdev->dma_mask = DMA_BIT_MASK(32);
return result & RIO_PORT_N_ERR_STS_PORT_OK;
}
-/**
- * rio_alloc_net- Allocate and configure a new RIO network
- * @port: Master port associated with the RIO network
+static void rio_scan_release_net(struct rio_net *net)
+{
+ 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
* @start: logical minimal start id for new net
*
- * 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.
+ * Allocates a new RIO network structure and initializes enumerator-specific
+ * part of it (if required).
+ * Returns a RIO network pointer on success or %NULL on failure.
*/
-static struct rio_net *rio_alloc_net(struct rio_mport *port,
- int do_enum, u16 start)
+static struct rio_net *rio_scan_alloc_net(struct rio_mport *mport,
+ int do_enum, u16 start)
{
struct rio_net *net;
- net = kzalloc(sizeof(struct rio_net), GFP_KERNEL);
+ net = rio_alloc_net(mport);
+
if (net && do_enum) {
- net->destid_table.table = kcalloc(
- BITS_TO_LONGS(RIO_MAX_ROUTE_ENTRIES(port->sys_size)),
- sizeof(long),
- GFP_KERNEL);
+ struct rio_id_table *idtab;
+ size_t size;
+
+ 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");
- kfree(net);
+ rio_free_net(net);
net = NULL;
} else {
- net->destid_table.start = start;
- net->destid_table.max =
- RIO_MAX_ROUTE_ENTRIES(port->sys_size);
- spin_lock_init(&net->destid_table.lock);
+ net->enum_data = idtab;
+ net->release = rio_scan_release_net;
+ idtab->start = start;
+ idtab->max = RIO_MAX_ROUTE_ENTRIES(mport->sys_size);
+ spin_lock_init(&idtab->lock);
}
}
if (net) {
- INIT_LIST_HEAD(&net->node);
- INIT_LIST_HEAD(&net->devices);
- INIT_LIST_HEAD(&net->switches);
- INIT_LIST_HEAD(&net->mports);
- list_add_tail(&port->nnode, &net->mports);
- net->hport = port;
- net->id = port->id;
+ net->id = mport->id;
+ net->hport = mport;
+ dev_set_name(&net->dev, "rnet_%d", net->id);
+ net->dev.parent = &mport->dev;
+ net->dev.release = rio_scan_release_dev;
+ rio_add_net(net);
}
+
return net;
}
/* If master port has an active link, allocate net and enum peers */
if (rio_mport_is_active(mport)) {
- net = rio_alloc_net(mport, 1, 0);
+ net = rio_scan_alloc_net(mport, 1, 0);
if (!net) {
printk(KERN_ERR "RIO: failed to allocate new net\n");
rc = -ENOMEM;
enum_done:
pr_debug("RIO: ... enumeration done\n");
- net = rio_alloc_net(mport, 0, 0);
+ net = rio_scan_alloc_net(mport, 0, 0);
if (!net) {
printk(KERN_ERR "RIO: Failed to allocate new net\n");
goto bail;
"Destination ID assignment to local RapidIO controllers");
static LIST_HEAD(rio_devices);
+static LIST_HEAD(rio_nets);
static DEFINE_SPINLOCK(rio_global_list_lock);
static LIST_HEAD(rio_mports);
}
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
* @rdev: RIO device
#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 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
* @dbells: List of doorbell events
* @node: Node in global 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
* @riores: RIO resources that this master port interfaces owns
* @inb_msg: RIO inbound message event descriptors
struct list_head dbells; /* list of doorbell events */
struct list_head node; /* node in global 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 riores[RIO_MAX_MPORT_RESOURCES];
struct rio_msg inb_msg[RIO_MAX_MBOX];
*/
#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
* @node: Node in global list of RIO networks
* @mports: List of master ports accessing this network
* @hport: Default port for accessing this network
* @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 list_head node; /* node in list of networks */
struct list_head mports; /* list of ports accessing net */
struct rio_mport *hport; /* primary port for accessing net */
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 {