aboutsummaryrefslogtreecommitdiff
path: root/drivers/rapidio
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/rapidio')
-rw-r--r--drivers/rapidio/Kconfig5
-rw-r--r--drivers/rapidio/Makefile4
-rw-r--r--drivers/rapidio/devices/Kconfig2
-rw-r--r--drivers/rapidio/devices/Makefile7
-rw-r--r--drivers/rapidio/devices/tsi721.c21
-rw-r--r--drivers/rapidio/devices/tsi721.h5
-rw-r--r--drivers/rapidio/devices/tsi721_dma.c146
-rw-r--r--drivers/rapidio/rio-driver.c44
-rw-r--r--drivers/rapidio/rio-scan.c182
-rw-r--r--drivers/rapidio/rio-sysfs.c123
-rw-r--r--drivers/rapidio/rio.c501
-rw-r--r--drivers/rapidio/rio.h49
-rw-r--r--drivers/rapidio/switches/Kconfig19
-rw-r--r--drivers/rapidio/switches/Makefile1
-rw-r--r--drivers/rapidio/switches/idt_gen2.c100
-rw-r--r--drivers/rapidio/switches/idtcps.c86
-rw-r--r--drivers/rapidio/switches/tsi500.c78
-rw-r--r--drivers/rapidio/switches/tsi568.c71
-rw-r--r--drivers/rapidio/switches/tsi57x.c81
19 files changed, 974 insertions, 551 deletions
diff --git a/drivers/rapidio/Kconfig b/drivers/rapidio/Kconfig
index 5ab056494bb..3e3be57e9a1 100644
--- a/drivers/rapidio/Kconfig
+++ b/drivers/rapidio/Kconfig
@@ -67,4 +67,9 @@ config RAPIDIO_ENUM_BASIC
endchoice
+menu "RapidIO Switch drivers"
+ depends on RAPIDIO
+
source "drivers/rapidio/switches/Kconfig"
+
+endmenu
diff --git a/drivers/rapidio/Makefile b/drivers/rapidio/Makefile
index 3036702ffe8..6271ada6993 100644
--- a/drivers/rapidio/Makefile
+++ b/drivers/rapidio/Makefile
@@ -1,7 +1,9 @@
#
# Makefile for RapidIO interconnect services
#
-obj-y += rio.o rio-access.o rio-driver.o rio-sysfs.o
+obj-$(CONFIG_RAPIDIO) += rapidio.o
+rapidio-y := rio.o rio-access.o rio-driver.o rio-sysfs.o
+
obj-$(CONFIG_RAPIDIO_ENUM_BASIC) += rio-scan.o
obj-$(CONFIG_RAPIDIO) += switches/
diff --git a/drivers/rapidio/devices/Kconfig b/drivers/rapidio/devices/Kconfig
index 12a9d7f7040..c4cb0877592 100644
--- a/drivers/rapidio/devices/Kconfig
+++ b/drivers/rapidio/devices/Kconfig
@@ -3,7 +3,7 @@
#
config RAPIDIO_TSI721
- bool "IDT Tsi721 PCI Express SRIO Controller support"
+ tristate "IDT Tsi721 PCI Express SRIO Controller support"
depends on RAPIDIO && PCIEPORTBUS
default "n"
---help---
diff --git a/drivers/rapidio/devices/Makefile b/drivers/rapidio/devices/Makefile
index 7b62860f34f..9432c494cf5 100644
--- a/drivers/rapidio/devices/Makefile
+++ b/drivers/rapidio/devices/Makefile
@@ -2,7 +2,6 @@
# Makefile for RapidIO devices
#
-obj-$(CONFIG_RAPIDIO_TSI721) += tsi721.o
-ifeq ($(CONFIG_RAPIDIO_DMA_ENGINE),y)
-obj-$(CONFIG_RAPIDIO_TSI721) += tsi721_dma.o
-endif
+obj-$(CONFIG_RAPIDIO_TSI721) += tsi721_mport.o
+tsi721_mport-y := tsi721.o
+tsi721_mport-$(CONFIG_RAPIDIO_DMA_ENGINE) += tsi721_dma.o
diff --git a/drivers/rapidio/devices/tsi721.c b/drivers/rapidio/devices/tsi721.c
index a8b2c23a7ef..2ca1a0b3ad5 100644
--- a/drivers/rapidio/devices/tsi721.c
+++ b/drivers/rapidio/devices/tsi721.c
@@ -768,15 +768,10 @@ static int tsi721_enable_msix(struct tsi721_device *priv)
}
#endif /* CONFIG_RAPIDIO_DMA_ENGINE */
- err = pci_enable_msix(priv->pdev, entries, ARRAY_SIZE(entries));
+ err = pci_enable_msix_exact(priv->pdev, entries, ARRAY_SIZE(entries));
if (err) {
- if (err > 0)
- dev_info(&priv->pdev->dev,
- "Only %d MSI-X vectors available, "
- "not using MSI-X\n", err);
- else
- dev_err(&priv->pdev->dev,
- "Failed to enable MSI-X (err=%d)\n", err);
+ dev_err(&priv->pdev->dev,
+ "Failed to enable MSI-X (err=%d)\n", err);
return err;
}
@@ -2256,6 +2251,7 @@ static int tsi721_setup_mport(struct tsi721_device *priv)
mport->phy_type = RIO_PHY_SERIAL;
mport->priv = (void *)priv;
mport->phys_efptr = 0x100;
+ mport->dev.parent = &pdev->dev;
priv->mport = mport;
INIT_LIST_HEAD(&mport->dbells);
@@ -2515,9 +2511,8 @@ static int __init tsi721_init(void)
return pci_register_driver(&tsi721_driver);
}
-static void __exit tsi721_exit(void)
-{
- pci_unregister_driver(&tsi721_driver);
-}
-
device_initcall(tsi721_init);
+
+MODULE_DESCRIPTION("IDT Tsi721 PCIExpress-to-SRIO bridge driver");
+MODULE_AUTHOR("Integrated Device Technology, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rapidio/devices/tsi721.h b/drivers/rapidio/devices/tsi721.h
index b4b0d83f9ef..0305675270e 100644
--- a/drivers/rapidio/devices/tsi721.h
+++ b/drivers/rapidio/devices/tsi721.h
@@ -644,6 +644,9 @@ enum tsi721_smsg_int_flag {
#ifdef CONFIG_RAPIDIO_DMA_ENGINE
+#define TSI721_BDMA_BD_RING_SZ 128
+#define TSI721_BDMA_MAX_BCOUNT (TSI721_DMAD_BCOUNT1 + 1)
+
struct tsi721_tx_desc {
struct dma_async_tx_descriptor txd;
struct tsi721_dma_desc *hw_desc;
@@ -652,6 +655,7 @@ struct tsi721_tx_desc {
u64 rio_addr;
/* upper 2-bits of 66-bit RIO address */
u8 rio_addr_u;
+ u32 bcount;
bool interrupt;
struct list_head desc_node;
struct list_head tx_list;
@@ -678,6 +682,7 @@ struct tsi721_bdma_chan {
struct list_head free_list;
dma_cookie_t completed_cookie;
struct tasklet_struct tasklet;
+ bool active;
};
#endif /* CONFIG_RAPIDIO_DMA_ENGINE */
diff --git a/drivers/rapidio/devices/tsi721_dma.c b/drivers/rapidio/devices/tsi721_dma.c
index 502663f5f7c..44341dc5b14 100644
--- a/drivers/rapidio/devices/tsi721_dma.c
+++ b/drivers/rapidio/devices/tsi721_dma.c
@@ -206,8 +206,8 @@ void tsi721_bdma_handler(struct tsi721_bdma_chan *bdma_chan)
{
/* Disable BDMA channel interrupts */
iowrite32(0, bdma_chan->regs + TSI721_DMAC_INTE);
-
- tasklet_schedule(&bdma_chan->tasklet);
+ if (bdma_chan->active)
+ tasklet_schedule(&bdma_chan->tasklet);
}
#ifdef CONFIG_PCI_MSI
@@ -287,6 +287,12 @@ struct tsi721_tx_desc *tsi721_desc_get(struct tsi721_bdma_chan *bdma_chan)
"desc %p not ACKed\n", tx_desc);
}
+ if (ret == NULL) {
+ dev_dbg(bdma_chan->dchan.device->dev,
+ "%s: unable to obtain tx descriptor\n", __func__);
+ goto err_out;
+ }
+
i = bdma_chan->wr_count_next % bdma_chan->bd_num;
if (i == bdma_chan->bd_num - 1) {
i = 0;
@@ -297,42 +303,24 @@ struct tsi721_tx_desc *tsi721_desc_get(struct tsi721_bdma_chan *bdma_chan)
tx_desc->txd.phys = bdma_chan->bd_phys +
i * sizeof(struct tsi721_dma_desc);
tx_desc->hw_desc = &((struct tsi721_dma_desc *)bdma_chan->bd_base)[i];
-
+err_out:
spin_unlock_bh(&bdma_chan->lock);
return ret;
}
static int
-tsi721_fill_desc(struct tsi721_bdma_chan *bdma_chan,
- struct tsi721_tx_desc *desc, struct scatterlist *sg,
+tsi721_desc_fill_init(struct tsi721_tx_desc *desc, struct scatterlist *sg,
enum dma_rtype rtype, u32 sys_size)
{
struct tsi721_dma_desc *bd_ptr = desc->hw_desc;
u64 rio_addr;
- if (sg_dma_len(sg) > TSI721_DMAD_BCOUNT1 + 1) {
- dev_err(bdma_chan->dchan.device->dev,
- "SG element is too large\n");
- return -EINVAL;
- }
-
- dev_dbg(bdma_chan->dchan.device->dev,
- "desc: 0x%llx, addr: 0x%llx len: 0x%x\n",
- (u64)desc->txd.phys, (unsigned long long)sg_dma_address(sg),
- sg_dma_len(sg));
-
- dev_dbg(bdma_chan->dchan.device->dev,
- "bd_ptr = %p did=%d raddr=0x%llx\n",
- bd_ptr, desc->destid, desc->rio_addr);
-
/* Initialize DMA descriptor */
bd_ptr->type_id = cpu_to_le32((DTYPE1 << 29) |
(rtype << 19) | desc->destid);
- if (desc->interrupt)
- bd_ptr->type_id |= cpu_to_le32(TSI721_DMAD_IOF);
bd_ptr->bcount = cpu_to_le32(((desc->rio_addr & 0x3) << 30) |
- (sys_size << 26) | sg_dma_len(sg));
+ (sys_size << 26));
rio_addr = (desc->rio_addr >> 2) |
((u64)(desc->rio_addr_u & 0x3) << 62);
bd_ptr->raddr_lo = cpu_to_le32(rio_addr & 0xffffffff);
@@ -346,6 +334,20 @@ tsi721_fill_desc(struct tsi721_bdma_chan *bdma_chan,
return 0;
}
+static int
+tsi721_desc_fill_end(struct tsi721_tx_desc *desc)
+{
+ struct tsi721_dma_desc *bd_ptr = desc->hw_desc;
+
+ /* Update DMA descriptor */
+ if (desc->interrupt)
+ bd_ptr->type_id |= cpu_to_le32(TSI721_DMAD_IOF);
+ bd_ptr->bcount |= cpu_to_le32(desc->bcount & TSI721_DMAD_BCOUNT1);
+
+ return 0;
+}
+
+
static void tsi721_dma_chain_complete(struct tsi721_bdma_chan *bdma_chan,
struct tsi721_tx_desc *desc)
{
@@ -562,7 +564,7 @@ static int tsi721_alloc_chan_resources(struct dma_chan *dchan)
}
#endif /* CONFIG_PCI_MSI */
- tasklet_enable(&bdma_chan->tasklet);
+ bdma_chan->active = true;
tsi721_bdma_interrupt_enable(bdma_chan, 1);
return bdma_chan->bd_num - 1;
@@ -576,9 +578,7 @@ err_out:
static void tsi721_free_chan_resources(struct dma_chan *dchan)
{
struct tsi721_bdma_chan *bdma_chan = to_tsi721_chan(dchan);
-#ifdef CONFIG_PCI_MSI
struct tsi721_device *priv = to_tsi721(dchan->device);
-#endif
LIST_HEAD(list);
dev_dbg(dchan->device->dev, "%s: Entry\n", __func__);
@@ -589,14 +589,25 @@ static void tsi721_free_chan_resources(struct dma_chan *dchan)
BUG_ON(!list_empty(&bdma_chan->active_list));
BUG_ON(!list_empty(&bdma_chan->queue));
- tasklet_disable(&bdma_chan->tasklet);
+ tsi721_bdma_interrupt_enable(bdma_chan, 0);
+ bdma_chan->active = false;
+
+#ifdef CONFIG_PCI_MSI
+ if (priv->flags & TSI721_USING_MSIX) {
+ synchronize_irq(priv->msix[TSI721_VECT_DMA0_DONE +
+ bdma_chan->id].vector);
+ synchronize_irq(priv->msix[TSI721_VECT_DMA0_INT +
+ bdma_chan->id].vector);
+ } else
+#endif
+ synchronize_irq(priv->pdev->irq);
+
+ tasklet_kill(&bdma_chan->tasklet);
spin_lock_bh(&bdma_chan->lock);
list_splice_init(&bdma_chan->free_list, &list);
spin_unlock_bh(&bdma_chan->lock);
- tsi721_bdma_interrupt_enable(bdma_chan, 0);
-
#ifdef CONFIG_PCI_MSI
if (priv->flags & TSI721_USING_MSIX) {
free_irq(priv->msix[TSI721_VECT_DMA0_DONE +
@@ -665,6 +676,7 @@ struct dma_async_tx_descriptor *tsi721_prep_rio_sg(struct dma_chan *dchan,
unsigned int i;
u32 sys_size = dma_to_mport(dchan->device)->sys_size;
enum dma_rtype rtype;
+ dma_addr_t next_addr = -1;
if (!sgl || !sg_len) {
dev_err(dchan->device->dev, "%s: No SG list\n", __func__);
@@ -695,36 +707,84 @@ struct dma_async_tx_descriptor *tsi721_prep_rio_sg(struct dma_chan *dchan,
for_each_sg(sgl, sg, sg_len, i) {
int err;
- dev_dbg(dchan->device->dev, "%s: sg #%d\n", __func__, i);
+ if (sg_dma_len(sg) > TSI721_BDMA_MAX_BCOUNT) {
+ dev_err(dchan->device->dev,
+ "%s: SG entry %d is too large\n", __func__, i);
+ goto err_desc_put;
+ }
+
+ /*
+ * If this sg entry forms contiguous block with previous one,
+ * try to merge it into existing DMA descriptor
+ */
+ if (desc) {
+ if (next_addr == sg_dma_address(sg) &&
+ desc->bcount + sg_dma_len(sg) <=
+ TSI721_BDMA_MAX_BCOUNT) {
+ /* Adjust byte count of the descriptor */
+ desc->bcount += sg_dma_len(sg);
+ goto entry_done;
+ }
+
+ /*
+ * Finalize this descriptor using total
+ * byte count value.
+ */
+ tsi721_desc_fill_end(desc);
+ dev_dbg(dchan->device->dev, "%s: desc final len: %d\n",
+ __func__, desc->bcount);
+ }
+
+ /*
+ * Obtain and initialize a new descriptor
+ */
desc = tsi721_desc_get(bdma_chan);
if (!desc) {
dev_err(dchan->device->dev,
- "Not enough descriptors available\n");
- goto err_desc_get;
+ "%s: Failed to get new descriptor for SG %d\n",
+ __func__, i);
+ goto err_desc_put;
}
- if (sg_is_last(sg))
- desc->interrupt = (flags & DMA_PREP_INTERRUPT) != 0;
- else
- desc->interrupt = false;
-
desc->destid = rext->destid;
desc->rio_addr = rio_addr;
desc->rio_addr_u = 0;
+ desc->bcount = sg_dma_len(sg);
- err = tsi721_fill_desc(bdma_chan, desc, sg, rtype, sys_size);
+ dev_dbg(dchan->device->dev,
+ "sg%d desc: 0x%llx, addr: 0x%llx len: %d\n",
+ i, (u64)desc->txd.phys,
+ (unsigned long long)sg_dma_address(sg),
+ sg_dma_len(sg));
+
+ dev_dbg(dchan->device->dev,
+ "bd_ptr = %p did=%d raddr=0x%llx\n",
+ desc->hw_desc, desc->destid, desc->rio_addr);
+
+ err = tsi721_desc_fill_init(desc, sg, rtype, sys_size);
if (err) {
dev_err(dchan->device->dev,
"Failed to build desc: %d\n", err);
- goto err_desc_get;
+ goto err_desc_put;
}
- rio_addr += sg_dma_len(sg);
+ next_addr = sg_dma_address(sg);
if (!first)
first = desc;
else
list_add_tail(&desc->desc_node, &first->tx_list);
+
+entry_done:
+ if (sg_is_last(sg)) {
+ desc->interrupt = (flags & DMA_PREP_INTERRUPT) != 0;
+ tsi721_desc_fill_end(desc);
+ dev_dbg(dchan->device->dev, "%s: desc final len: %d\n",
+ __func__, desc->bcount);
+ } else {
+ rio_addr += sg_dma_len(sg);
+ next_addr += sg_dma_len(sg);
+ }
}
first->txd.cookie = -EBUSY;
@@ -732,7 +792,7 @@ struct dma_async_tx_descriptor *tsi721_prep_rio_sg(struct dma_chan *dchan,
return &first->txd;
-err_desc_get:
+err_desc_put:
tsi721_desc_put(bdma_chan, first);
return NULL;
}
@@ -783,13 +843,14 @@ int tsi721_register_dma(struct tsi721_device *priv)
if (i == TSI721_DMACH_MAINT)
continue;
- bdma_chan->bd_num = 64;
+ bdma_chan->bd_num = TSI721_BDMA_BD_RING_SZ;
bdma_chan->regs = priv->regs + TSI721_DMAC_BASE(i);
bdma_chan->dchan.device = &mport->dma;
bdma_chan->dchan.cookie = 1;
bdma_chan->dchan.chan_id = i;
bdma_chan->id = i;
+ bdma_chan->active = false;
spin_lock_init(&bdma_chan->lock);
@@ -799,7 +860,6 @@ int tsi721_register_dma(struct tsi721_device *priv)
tasklet_init(&bdma_chan->tasklet, tsi721_dma_tasklet,
(unsigned long)bdma_chan);
- tasklet_disable(&bdma_chan->tasklet);
list_add_tail(&bdma_chan->dchan.device_node,
&mport->dma.channels);
}
diff --git a/drivers/rapidio/rio-driver.c b/drivers/rapidio/rio-driver.c
index a0c875563d7..f301f059bb8 100644
--- a/drivers/rapidio/rio-driver.c
+++ b/drivers/rapidio/rio-driver.c
@@ -167,7 +167,6 @@ void rio_unregister_driver(struct rio_driver *rdrv)
void rio_attach_device(struct rio_dev *rdev)
{
rdev->dev.bus = &rio_bus_type;
- rdev->dev.parent = &rio_bus;
}
EXPORT_SYMBOL_GPL(rio_attach_device);
@@ -199,30 +198,57 @@ static int rio_match_bus(struct device *dev, struct device_driver *drv)
out:return 0;
}
-struct device rio_bus = {
- .init_name = "rapidio",
+static int rio_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+ struct rio_dev *rdev;
+
+ if (!dev)
+ return -ENODEV;
+
+ rdev = to_rio_dev(dev);
+ if (!rdev)
+ return -ENODEV;
+
+ if (add_uevent_var(env, "MODALIAS=rapidio:v%04Xd%04Xav%04Xad%04X",
+ rdev->vid, rdev->did, rdev->asm_vid, rdev->asm_did))
+ return -ENOMEM;
+ return 0;
+}
+
+struct class rio_mport_class = {
+ .name = "rapidio_port",
+ .owner = THIS_MODULE,
+ .dev_groups = rio_mport_groups,
};
+EXPORT_SYMBOL_GPL(rio_mport_class);
struct bus_type rio_bus_type = {
.name = "rapidio",
.match = rio_match_bus,
- .dev_attrs = rio_dev_attrs,
- .bus_attrs = rio_bus_attrs,
+ .dev_groups = rio_dev_groups,
+ .bus_groups = rio_bus_groups,
.probe = rio_device_probe,
.remove = rio_device_remove,
+ .uevent = rio_uevent,
};
/**
* rio_bus_init - Register the RapidIO bus with the device model
*
- * Registers the RIO bus device and RIO bus type with the Linux
+ * Registers the RIO mport device class and RIO bus type with the Linux
* device model.
*/
static int __init rio_bus_init(void)
{
- if (device_register(&rio_bus) < 0)
- printk("RIO: failed to register RIO bus device\n");
- return bus_register(&rio_bus_type);
+ int ret;
+
+ ret = class_register(&rio_mport_class);
+ if (!ret) {
+ ret = bus_register(&rio_bus_type);
+ if (ret)
+ class_unregister(&rio_mport_class);
+ }
+ return ret;
}
postcore_initcall(rio_bus_init);
diff --git a/drivers/rapidio/rio-scan.c b/drivers/rapidio/rio-scan.c
index 4c15dbf8108..47a1b2ea76c 100644
--- a/drivers/rapidio/rio-scan.c
+++ b/drivers/rapidio/rio-scan.c
@@ -406,6 +406,7 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
rio_mport_write_config_32(port, destid, hopcount,
RIO_COMPONENT_TAG_CSR, next_comptag);
rdev->comp_tag = next_comptag++;
+ rdev->do_enum = true;
} else {
rio_mport_read_config_32(port, destid, hopcount,
RIO_COMPONENT_TAG_CSR,
@@ -432,8 +433,8 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
/* If a PE has both switch and other functions, show it as a switch */
if (rio_is_switch(rdev)) {
rswitch = rdev->rswitch;
- rswitch->switchid = rdev->comp_tag & RIO_CTAG_UDEVID;
rswitch->port_ok = 0;
+ spin_lock_init(&rswitch->lock);
rswitch->route_table = kzalloc(sizeof(u8)*
RIO_MAX_ROUTE_ENTRIES(port->sys_size),
GFP_KERNEL);
@@ -444,12 +445,10 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
rdid++)
rswitch->route_table[rdid] = RIO_INVALID_ROUTE;
dev_set_name(&rdev->dev, "%02x:s:%04x", rdev->net->id,
- rswitch->switchid);
- rio_switch_init(rdev, do_enum);
+ rdev->comp_tag & RIO_CTAG_UDEVID);
- if (do_enum && rswitch->clr_table)
- rswitch->clr_table(port, destid, hopcount,
- RIO_GLOBAL_TABLE);
+ if (do_enum)
+ rio_route_clr_table(rdev, RIO_GLOBAL_TABLE, 0);
list_add_tail(&rswitch->node, &net->switches);
@@ -459,9 +458,10 @@ static struct rio_dev *rio_setup_device(struct rio_net *net,
rio_enable_rx_tx_port(port, 0, destid, hopcount, 0);
dev_set_name(&rdev->dev, "%02x:e:%04x", rdev->net->id,
- rdev->destid);
+ rdev->comp_tag & RIO_CTAG_UDEVID);
}
+ rdev->dev.parent = &port->dev;
rio_attach_device(rdev);
device_initialize(&rdev->dev);
@@ -533,156 +533,6 @@ rio_sport_is_active(struct rio_mport *port, u16 destid, u8 hopcount, int sport)
}
/**
- * rio_lock_device - Acquires host device lock for specified device
- * @port: Master port to send transaction
- * @destid: Destination ID for device/switch
- * @hopcount: Hopcount to reach switch
- * @wait_ms: Max wait time in msec (0 = no timeout)
- *
- * Attepts to acquire host device lock for specified device
- * Returns 0 if device lock acquired or EINVAL if timeout expires.
- */
-static int
-rio_lock_device(struct rio_mport *port, u16 destid, u8 hopcount, int wait_ms)
-{
- u32 result;
- int tcnt = 0;
-
- /* Attempt to acquire device lock */
- rio_mport_write_config_32(port, destid, hopcount,
- RIO_HOST_DID_LOCK_CSR, port->host_deviceid);
- rio_mport_read_config_32(port, destid, hopcount,
- RIO_HOST_DID_LOCK_CSR, &result);
-
- while (result != port->host_deviceid) {
- if (wait_ms != 0 && tcnt == wait_ms) {
- pr_debug("RIO: timeout when locking device %x:%x\n",
- destid, hopcount);
- return -EINVAL;
- }
-
- /* Delay a bit */
- mdelay(1);
- tcnt++;
- /* Try to acquire device lock again */
- rio_mport_write_config_32(port, destid,
- hopcount,
- RIO_HOST_DID_LOCK_CSR,
- port->host_deviceid);
- rio_mport_read_config_32(port, destid,
- hopcount,
- RIO_HOST_DID_LOCK_CSR, &result);
- }
-
- return 0;
-}
-
-/**
- * rio_unlock_device - Releases host device lock for specified device
- * @port: Master port to send transaction
- * @destid: Destination ID for device/switch
- * @hopcount: Hopcount to reach switch
- *
- * Returns 0 if device lock released or EINVAL if fails.
- */
-static int
-rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount)
-{
- u32 result;
-
- /* Release device lock */
- rio_mport_write_config_32(port, destid,
- hopcount,
- RIO_HOST_DID_LOCK_CSR,
- port->host_deviceid);
- rio_mport_read_config_32(port, destid, hopcount,
- RIO_HOST_DID_LOCK_CSR, &result);
- if ((result & 0xffff) != 0xffff) {
- pr_debug("RIO: badness when releasing device lock %x:%x\n",
- destid, hopcount);
- return -EINVAL;
- }
-
- return 0;
-}
-
-/**
- * rio_route_add_entry- Add a route entry to a switch routing table
- * @rdev: RIO device
- * @table: Routing table ID
- * @route_destid: Destination ID to be routed
- * @route_port: Port number to be routed
- * @lock: lock switch device flag
- *
- * Calls the switch specific add_entry() method to add a route entry
- * on a switch. The route table can be specified using the @table
- * argument if a switch has per port routing tables or the normal
- * use is to specific all tables (or the global table) by passing
- * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL
- * on failure.
- */
-static int
-rio_route_add_entry(struct rio_dev *rdev,
- u16 table, u16 route_destid, u8 route_port, int lock)
-{
- int rc;
-
- if (lock) {
- rc = rio_lock_device(rdev->net->hport, rdev->destid,
- rdev->hopcount, 1000);
- if (rc)
- return rc;
- }
-
- rc = rdev->rswitch->add_entry(rdev->net->hport, rdev->destid,
- rdev->hopcount, table,
- route_destid, route_port);
- if (lock)
- rio_unlock_device(rdev->net->hport, rdev->destid,
- rdev->hopcount);
-
- return rc;
-}
-
-/**
- * rio_route_get_entry- Read a route entry in a switch routing table
- * @rdev: RIO device
- * @table: Routing table ID
- * @route_destid: Destination ID to be routed
- * @route_port: Pointer to read port number into
- * @lock: lock switch device flag
- *
- * Calls the switch specific get_entry() method to read a route entry
- * in a switch. The route table can be specified using the @table
- * argument if a switch has per port routing tables or the normal
- * use is to specific all tables (or the global table) by passing
- * %RIO_GLOBAL_TABLE in @table. Returns %0 on success or %-EINVAL
- * on failure.
- */
-static int
-rio_route_get_entry(struct rio_dev *rdev, u16 table,
- u16 route_destid, u8 *route_port, int lock)
-{
- int rc;
-
- if (lock) {
- rc = rio_lock_device(rdev->net->hport, rdev->destid,
- rdev->hopcount, 1000);
- if (rc)
- return rc;
- }
-
- rc = rdev->rswitch->get_entry(rdev->net->hport, rdev->destid,
- rdev->hopcount, table,
- route_destid, route_port);
- if (lock)
- rio_unlock_device(rdev->net->hport, rdev->destid,
- rdev->hopcount);
-
- return rc;
-}
-
-/**
* rio_get_host_deviceid_lock- Reads the Host Device ID Lock CSR on a device
* @port: Master port to send transaction
* @hopcount: Number of hops to the device
@@ -1094,12 +944,9 @@ static void rio_update_route_tables(struct rio_net *net)
sport = RIO_GET_PORT_NUM(swrdev->swpinfo);
- if (rswitch->add_entry) {
- rio_route_add_entry(swrdev,
- RIO_GLOBAL_TABLE, destid,
- sport, 0);
- rswitch->route_table[destid] = sport;
- }
+ rio_route_add_entry(swrdev, RIO_GLOBAL_TABLE,
+ destid, sport, 0);
+ rswitch->route_table[destid] = sport;
}
}
}
@@ -1115,8 +962,8 @@ static void rio_update_route_tables(struct rio_net *net)
static void rio_init_em(struct rio_dev *rdev)
{
if (rio_is_switch(rdev) && (rdev->em_efptr) &&
- (rdev->rswitch->em_init)) {
- rdev->rswitch->em_init(rdev);
+ rdev->rswitch->ops && rdev->rswitch->ops->em_init) {
+ rdev->rswitch->ops->em_init(rdev);
}
}
@@ -1141,7 +988,7 @@ static void rio_pw_enable(struct rio_mport *port, int enable)
* link, then start recursive peer enumeration. Returns %0 if
* enumeration succeeds or %-EBUSY if enumeration fails.
*/
-int rio_enum_mport(struct rio_mport *mport, u32 flags)
+static int rio_enum_mport(struct rio_mport *mport, u32 flags)
{
struct rio_net *net = NULL;
int rc = 0;
@@ -1256,7 +1103,7 @@ static void rio_build_route_tables(struct rio_net *net)
* peer discovery. Returns %0 if discovery succeeds or %-EBUSY
* on failure.
*/
-int rio_disc_mport(struct rio_mport *mport, u32 flags)
+static int rio_disc_mport(struct rio_mport *mport, u32 flags)
{
struct rio_net *net = NULL;
unsigned long to_end;
@@ -1315,6 +1162,7 @@ bail:
}
static struct rio_scan rio_scan_ops = {
+ .owner = THIS_MODULE,
.enumerate = rio_enum_mport,
.discover = rio_disc_mport,
};
diff --git a/drivers/rapidio/rio-sysfs.c b/drivers/rapidio/rio-sysfs.c
index 66d4acd5e18..cdb005c0094 100644
--- a/drivers/rapidio/rio-sysfs.c
+++ b/drivers/rapidio/rio-sysfs.c
@@ -27,6 +27,7 @@ field##_show(struct device *dev, struct device_attribute *attr, char *buf) \
\
return sprintf(buf, format_string, rdev->field); \
} \
+static DEVICE_ATTR_RO(field);
rio_config_attr(did, "0x%04x\n");
rio_config_attr(vid, "0x%04x\n");
@@ -54,6 +55,7 @@ static ssize_t routes_show(struct device *dev, struct device_attribute *attr, ch
return (str - buf);
}
+static DEVICE_ATTR_RO(routes);
static ssize_t lprev_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -63,6 +65,7 @@ static ssize_t lprev_show(struct device *dev,
return sprintf(buf, "%s\n",
(rdev->prev) ? rio_name(rdev->prev) : "root");
}
+static DEVICE_ATTR_RO(lprev);
static ssize_t lnext_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -83,22 +86,39 @@ static ssize_t lnext_show(struct device *dev,
return str - buf;
}
+static DEVICE_ATTR_RO(lnext);
-struct device_attribute rio_dev_attrs[] = {
- __ATTR_RO(did),
- __ATTR_RO(vid),
- __ATTR_RO(device_rev),
- __ATTR_RO(asm_did),
- __ATTR_RO(asm_vid),
- __ATTR_RO(asm_rev),
- __ATTR_RO(lprev),
- __ATTR_RO(destid),
- __ATTR_NULL,
+static ssize_t modalias_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct rio_dev *rdev = to_rio_dev(dev);
+
+ return sprintf(buf, "rapidio:v%04Xd%04Xav%04Xad%04X\n",
+ rdev->vid, rdev->did, rdev->asm_vid, rdev->asm_did);
+}
+static DEVICE_ATTR_RO(modalias);
+
+static struct attribute *rio_dev_attrs[] = {
+ &dev_attr_did.attr,
+ &dev_attr_vid.attr,
+ &dev_attr_device_rev.attr,
+ &dev_attr_asm_did.attr,
+ &dev_attr_asm_vid.attr,
+ &dev_attr_asm_rev.attr,
+ &dev_attr_lprev.attr,
+ &dev_attr_destid.attr,
+ &dev_attr_modalias.attr,
+ NULL,
};
-static DEVICE_ATTR(routes, S_IRUGO, routes_show, NULL);
-static DEVICE_ATTR(lnext, S_IRUGO, lnext_show, NULL);
-static DEVICE_ATTR(hopcount, S_IRUGO, hopcount_show, NULL);
+static const struct attribute_group rio_dev_group = {
+ .attrs = rio_dev_attrs,
+};
+
+const struct attribute_group *rio_dev_groups[] = {
+ &rio_dev_group,
+ NULL,
+};
static ssize_t
rio_read_config(struct file *filp, struct kobject *kobj,
@@ -257,8 +277,6 @@ int rio_create_sysfs_dev_files(struct rio_dev *rdev)
err |= device_create_file(&rdev->dev, &dev_attr_routes);
err |= device_create_file(&rdev->dev, &dev_attr_lnext);
err |= device_create_file(&rdev->dev, &dev_attr_hopcount);
- if (!err && rdev->rswitch->sw_sysfs)
- err = rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_CREATE);
}
if (err)
@@ -281,8 +299,6 @@ void rio_remove_sysfs_dev_files(struct rio_dev *rdev)
device_remove_file(&rdev->dev, &dev_attr_routes);
device_remove_file(&rdev->dev, &dev_attr_lnext);
device_remove_file(&rdev->dev, &dev_attr_hopcount);
- if (rdev->rswitch->sw_sysfs)
- rdev->rswitch->sw_sysfs(rdev, RIO_SW_SYSFS_REMOVE);
}
}
@@ -290,7 +306,6 @@ static ssize_t bus_scan_store(struct bus_type *bus, const char *buf,
size_t count)
{
long val;
- struct rio_mport *port = NULL;
int rc;
if (kstrtol(buf, 0, &val) < 0)
@@ -304,29 +319,65 @@ static ssize_t bus_scan_store(struct bus_type *bus, const char *buf,
if (val < 0 || val >= RIO_MAX_MPORTS)
return -EINVAL;
- port = rio_find_mport((int)val);
-
- if (!port) {
- pr_debug("RIO: %s: mport_%d not available\n",
- __func__, (int)val);
- return -EINVAL;
- }
-
- if (!port->nscan)
- return -EINVAL;
-
- if (port->host_deviceid >= 0)
- rc = port->nscan->enumerate(port, 0);
- else
- rc = port->nscan->discover(port, RIO_SCAN_ENUM_NO_WAIT);
+ rc = rio_mport_scan((int)val);
exit:
if (!rc)
rc = count;
return rc;
}
+static BUS_ATTR(scan, (S_IWUSR|S_IWGRP), NULL, bus_scan_store);
+
+static struct attribute *rio_bus_attrs[] = {
+ &bus_attr_scan.attr,
+ NULL,
+};
+
+static const struct attribute_group rio_bus_group = {
+ .attrs = rio_bus_attrs,
+};
+
+const struct attribute_group *rio_bus_groups[] = {
+ &rio_bus_group,
+ NULL,
+};
+
+static ssize_t
+port_destid_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct rio_mport *mport = to_rio_mport(dev);
+
+ if (mport)
+ return sprintf(buf, "0x%04x\n", mport->host_deviceid);
+ else
+ return -ENODEV;
+}
+static DEVICE_ATTR_RO(port_destid);
+
+static ssize_t sys_size_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct rio_mport *mport = to_rio_mport(dev);
+
+ if (mport)
+ return sprintf(buf, "%u\n", mport->sys_size);
+ else
+ return -ENODEV;
+}
+static DEVICE_ATTR_RO(sys_size);
+
+static struct attribute *rio_mport_attrs[] = {
+ &dev_attr_port_destid.attr,
+ &dev_attr_sys_size.attr,
+ NULL,
+};
+
+static const struct attribute_group rio_mport_group = {
+ .attrs = rio_mport_attrs,
+};
-struct bus_attribute rio_bus_attrs[] = {
- __ATTR(scan, (S_IWUSR|S_IWGRP), NULL, bus_scan_store),
- __ATTR_NULL
+const struct attribute_group *rio_mport_groups[] = {
+ &rio_mport_group,
+ NULL,
};
diff --git a/drivers/rapidio/rio.c b/drivers/rapidio/rio.c
index cb1c08996fb..a54ba0494dd 100644
--- a/drivers/rapidio/rio.c
+++ b/drivers/rapidio/rio.c
@@ -5,9 +5,8 @@
* Copyright 2005 MontaVista Software, Inc.
* Matt Porter <mporter@kernel.crashing.org>
*
- * Copyright 2009 Integrated Device Technology, Inc.
+ * Copyright 2009 - 2013 Integrated Device Technology, Inc.
* Alex Bounine <alexandre.bounine@idt.com>
- * - Added Port-Write/Error Management initialization and handling
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -31,10 +30,22 @@
#include "rio.h"
+MODULE_DESCRIPTION("RapidIO Subsystem Core");
+MODULE_AUTHOR("Matt Porter <mporter@kernel.crashing.org>");
+MODULE_AUTHOR("Alexandre Bounine <alexandre.bounine@idt.com>");
+MODULE_LICENSE("GPL");
+
+static int hdid[RIO_MAX_MPORTS];
+static int ids_num;
+module_param_array(hdid, int, &ids_num, 0);
+MODULE_PARM_DESC(hdid,
+ "Destination ID assignment to local RapidIO controllers");
+
static LIST_HEAD(rio_devices);
static DEFINE_SPINLOCK(rio_global_list_lock);
static LIST_HEAD(rio_mports);
+static LIST_HEAD(rio_scans);
static DEFINE_MUTEX(rio_mport_list_lock);
static unsigned char next_portid;
static DEFINE_SPINLOCK(rio_mmap_lock);
@@ -580,44 +591,6 @@ int rio_set_port_lockout(struct rio_dev *rdev, u32 pnum, int lock)
EXPORT_SYMBOL_GPL(rio_set_port_lockout);
/**
- * rio_switch_init - Sets switch operations for a particular vendor switch
- * @rdev: RIO device
- * @do_enum: Enumeration/Discovery mode flag
- *
- * Searches the RIO switch ops table for known switch types. If the vid
- * and did match a switch table entry, then call switch initialization
- * routine to setup switch-specific routines.
- */
-void rio_switch_init(struct rio_dev *rdev, int do_enum)
-{
- struct rio_switch_ops *cur = __start_rio_switch_ops;
- struct rio_switch_ops *end = __end_rio_switch_ops;
-
- while (cur < end) {
- if ((cur->vid == rdev->vid) && (cur->did == rdev->did)) {
- pr_debug("RIO: calling init routine for %s\n",
- rio_name(rdev));
- cur->init_hook(rdev, do_enum);
- break;
- }
- cur++;
- }
-
- if ((cur >= end) && (rdev->pef & RIO_PEF_STD_RT)) {
- pr_debug("RIO: adding STD routing ops for %s\n",
- rio_name(rdev));
- rdev->rswitch->add_entry = rio_std_route_add_entry;
- rdev->rswitch->get_entry = rio_std_route_get_entry;
- rdev->rswitch->clr_table = rio_std_route_clr_table;
- }
-
- if (!rdev->rswitch->add_entry || !rdev->rswitch->get_entry)
- printk(KERN_ERR "RIO: missing routing ops for %s\n",
- rio_name(rdev));
-}
-EXPORT_SYMBOL_GPL(rio_switch_init);
-
-/**
* rio_enable_rx_tx_port - enable input receiver and output transmitter of
* given port
* @port: Master port associated with the RIO network
@@ -970,8 +943,8 @@ int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
/*
* Process the port-write notification from switch
*/
- if (rdev->rswitch->em_handle)
- rdev->rswitch->em_handle(rdev, portnum);
+ if (rdev->rswitch->ops && rdev->rswitch->ops->em_handle)
+ rdev->rswitch->ops->em_handle(rdev, portnum);
rio_read_config_32(rdev,
rdev->phys_efptr + RIO_PORT_N_ERR_STS_CSR(portnum),
@@ -1207,8 +1180,9 @@ struct rio_dev *rio_get_device(u16 vid, u16 did, struct rio_dev *from)
* @route_destid: destID entry in the RT
* @route_port: destination port for specified destID
*/
-int rio_std_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
- u16 table, u16 route_destid, u8 route_port)
+static int
+rio_std_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+ u16 table, u16 route_destid, u8 route_port)
{
if (table == RIO_GLOBAL_TABLE) {
rio_mport_write_config_32(mport, destid, hopcount,
@@ -1234,8 +1208,9 @@ int rio_std_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
* @route_destid: destID entry in the RT
* @route_port: returned destination port for specified destID
*/
-int rio_std_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
- u16 table, u16 route_destid, u8 *route_port)
+static int
+rio_std_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
+ u16 table, u16 route_destid, u8 *route_port)
{
u32 result;
@@ -1259,8 +1234,9 @@ int rio_std_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
* @hopcount: Number of switch hops to the device
* @table: routing table ID (global or port-specific)
*/
-int rio_std_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
- u16 table)
+static int
+rio_std_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
+ u16 table)
{
u32 max_destid = 0xff;
u32 i, pef, id_inc = 1, ext_cfg = 0;
@@ -1301,6 +1277,234 @@ int rio_std_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
return 0;
}
+/**
+ * rio_lock_device - Acquires host device lock for specified device
+ * @port: Master port to send transaction
+ * @destid: Destination ID for device/switch
+ * @hopcount: Hopcount to reach switch
+ * @wait_ms: Max wait time in msec (0 = no timeout)
+ *
+ * Attepts to acquire host device lock for specified device
+ * Returns 0 if device lock acquired or EINVAL if timeout expires.
+ */
+int rio_lock_device(struct rio_mport *port, u16 destid,
+ u8 hopcount, int wait_ms)
+{
+ u32 result;
+ int tcnt = 0;
+
+ /* Attempt to acquire device lock */
+ rio_mport_write_config_32(port, destid, hopcount,
+ RIO_HOST_DID_LOCK_CSR, port->host_deviceid);
+ rio_mport_read_config_32(port, destid, hopcount,
+ RIO_HOST_DID_LOCK_CSR, &result);
+
+ while (result != port->host_deviceid) {
+ if (wait_ms != 0 && tcnt == wait_ms) {
+ pr_debug("RIO: timeout when locking device %x:%x\n",
+ destid, hopcount);
+ return -EINVAL;
+ }
+
+ /* Delay a bit */
+ mdelay(1);
+ tcnt++;
+ /* Try to acquire device lock again */
+ rio_mport_write_config_32(port, destid,
+ hopcount,
+ RIO_HOST_DID_LOCK_CSR,
+ port->host_deviceid);
+ rio_mport_read_config_32(port, destid,
+ hopcount,
+ RIO_HOST_DID_LOCK_CSR, &result);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rio_lock_device);
+
+/**
+ * rio_unlock_device - Releases host device lock for specified device
+ * @port: Master port to send transaction
+ * @destid: Destination ID for device/switch
+ * @hopcount: Hopcount to reach switch
+ *
+ * Returns 0 if device lock released or EINVAL if fails.
+ */
+int rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount)
+{
+ u32 result;
+
+ /* Release device lock */
+ rio_mport_write_config_32(port, destid,
+ hopcount,
+ RIO_HOST_DID_LOCK_CSR,
+ port->host_deviceid);
+ rio_mport_read_config_32(port, destid, hopcount,
+ RIO_HOST_DID_LOCK_CSR, &result);
+ if ((result & 0xffff) != 0xffff) {
+ pr_debug("RIO: badness when releasing device lock %x:%x\n",
+ destid, hopcount);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rio_unlock_device);
+
+/**
+ * rio_route_add_entry- Add a route entry to a switch routing table
+ * @rdev: RIO device
+ * @table: Routing table ID
+ * @route_destid: Destination ID to be routed
+ * @route_port: Port number to be routed
+ * @lock: apply a hardware lock on switch device flag (1=lock, 0=no_lock)
+ *
+ * If available calls the switch specific add_entry() method to add a route
+ * entry into a switch routing table. Otherwise uses standard RT update method
+ * as defined by RapidIO specification. A specific routing table can be selected
+ * using the @table argument if a switch has per port routing tables or
+ * the standard (or global) table may be used by passing
+ * %RIO_GLOBAL_TABLE in @table.
+ *
+ * Returns %0 on success or %-EINVAL on failure.
+ */
+int rio_route_add_entry(struct rio_dev *rdev,
+ u16 table, u16 route_destid, u8 route_port, int lock)
+{
+ int rc = -EINVAL;
+ struct rio_switch_ops *ops = rdev->rswitch->ops;
+
+ if (lock) {
+ rc = rio_lock_device(rdev->net->hport, rdev->destid,
+ rdev->hopcount, 1000);
+ if (rc)
+ return rc;
+ }
+
+ spin_lock(&rdev->rswitch->lock);
+
+ if (ops == NULL || ops->add_entry == NULL) {
+ rc = rio_std_route_add_entry(rdev->net->hport, rdev->destid,
+ rdev->hopcount, table,
+ route_destid, route_port);
+ } else if (try_module_get(ops->owner)) {
+ rc = ops->add_entry(rdev->net->hport, rdev->destid,
+ rdev->hopcount, table, route_destid,
+ route_port);
+ module_put(ops->owner);
+ }
+
+ spin_unlock(&rdev->rswitch->lock);
+
+ if (lock)
+ rio_unlock_device(rdev->net->hport, rdev->destid,
+ rdev->hopcount);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(rio_route_add_entry);
+
+/**
+ * rio_route_get_entry- Read an entry from a switch routing table
+ * @rdev: RIO device
+ * @table: Routing table ID
+ * @route_destid: Destination ID to be routed
+ * @route_port: Pointer to read port number into
+ * @lock: apply a hardware lock on switch device flag (1=lock, 0=no_lock)
+ *
+ * If available calls the switch specific get_entry() method to fetch a route
+ * entry from a switch routing table. Otherwise uses standard RT read method
+ * as defined by RapidIO specification. A specific routing table can be selected
+ * using the @table argument if a switch has per port routing tables or
+ * the standard (or global) table may be used by passing
+ * %RIO_GLOBAL_TABLE in @table.
+ *
+ * Returns %0 on success or %-EINVAL on failure.
+ */
+int rio_route_get_entry(struct rio_dev *rdev, u16 table,
+ u16 route_destid, u8 *route_port, int lock)
+{
+ int rc = -EINVAL;
+ struct rio_switch_ops *ops = rdev->rswitch->ops;
+
+ if (lock) {
+ rc = rio_lock_device(rdev->net->hport, rdev->destid,
+ rdev->hopcount, 1000);
+ if (rc)
+ return rc;
+ }
+
+ spin_lock(&rdev->rswitch->lock);
+
+ if (ops == NULL || ops->get_entry == NULL) {
+ rc = rio_std_route_get_entry(rdev->net->hport, rdev->destid,
+ rdev->hopcount, table,
+ route_destid, route_port);
+ } else if (try_module_get(ops->owner)) {
+ rc = ops->get_entry(rdev->net->hport, rdev->destid,
+ rdev->hopcount, table, route_destid,
+ route_port);
+ module_put(ops->owner);
+ }
+
+ spin_unlock(&rdev->rswitch->lock);
+
+ if (lock)
+ rio_unlock_device(rdev->net->hport, rdev->destid,
+ rdev->hopcount);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(rio_route_get_entry);
+
+/**
+ * rio_route_clr_table - Clear a switch routing table
+ * @rdev: RIO device
+ * @table: Routing table ID
+ * @lock: apply a hardware lock on switch device flag (1=lock, 0=no_lock)
+ *
+ * If available calls the switch specific clr_table() method to clear a switch
+ * routing table. Otherwise uses standard RT write method as defined by RapidIO
+ * specification. A specific routing table can be selected using the @table
+ * argument if a switch has per port routing tables or the standard (or global)
+ * table may be used by passing %RIO_GLOBAL_TABLE in @table.
+ *
+ * Returns %0 on success or %-EINVAL on failure.
+ */
+int rio_route_clr_table(struct rio_dev *rdev, u16 table, int lock)
+{
+ int rc = -EINVAL;
+ struct rio_switch_ops *ops = rdev->rswitch->ops;
+
+ if (lock) {
+ rc = rio_lock_device(rdev->net->hport, rdev->destid,
+ rdev->hopcount, 1000);
+ if (rc)
+ return rc;
+ }
+
+ spin_lock(&rdev->rswitch->lock);
+
+ if (ops == NULL || ops->clr_table == NULL) {
+ rc = rio_std_route_clr_table(rdev->net->hport, rdev->destid,
+ rdev->hopcount, table);
+ } else if (try_module_get(ops->owner)) {
+ rc = ops->clr_table(rdev->net->hport, rdev->destid,
+ rdev->hopcount, table);
+
+ module_put(ops->owner);
+ }
+
+ spin_unlock(&rdev->rswitch->lock);
+
+ if (lock)
+ rio_unlock_device(rdev->net->hport, rdev->destid,
+ rdev->hopcount);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(rio_route_clr_table);
+
#ifdef CONFIG_RAPIDIO_DMA_ENGINE
static bool rio_chan_filter(struct dma_chan *chan, void *arg)
@@ -1410,34 +1614,73 @@ found:
* rio_register_scan - enumeration/discovery method registration interface
* @mport_id: mport device ID for which fabric scan routine has to be set
* (RIO_MPORT_ANY = set for all available mports)
- * @scan_ops: enumeration/discovery control structure
+ * @scan_ops: enumeration/discovery operations structure
+ *
+ * Registers enumeration/discovery operations with RapidIO subsystem and
+ * attaches it to the specified mport device (or all available mports
+ * if RIO_MPORT_ANY is specified).
*
- * Assigns enumeration or discovery method to the specified mport device (or all
- * available mports if RIO_MPORT_ANY is specified).
* Returns error if the mport already has an enumerator attached to it.
- * In case of RIO_MPORT_ANY ignores ports with valid scan routines and returns
- * an error if was unable to find at least one available mport.
+ * In case of RIO_MPORT_ANY skips mports with valid scan routines (no error).
*/
int rio_register_scan(int mport_id, struct rio_scan *scan_ops)
{
struct rio_mport *port;
- int rc = -EBUSY;
+ struct rio_scan_node *scan;
+ int rc = 0;
- mutex_lock(&rio_mport_list_lock);
- list_for_each_entry(port, &rio_mports, node) {
- if (port->id == mport_id || mport_id == RIO_MPORT_ANY) {
- if (port->nscan && mport_id == RIO_MPORT_ANY)
- continue;
- else if (port->nscan)
- break;
+ pr_debug("RIO: %s for mport_id=%d\n", __func__, mport_id);
- port->nscan = scan_ops;
- rc = 0;
+ if ((mport_id != RIO_MPORT_ANY && mport_id >= RIO_MAX_MPORTS) ||
+ !scan_ops)
+ return -EINVAL;
- if (mport_id != RIO_MPORT_ANY)
- break;
+ mutex_lock(&rio_mport_list_lock);
+
+ /*
+ * Check if there is another enumerator already registered for
+ * the same mport ID (including RIO_MPORT_ANY). Multiple enumerators
+ * for the same mport ID are not supported.
+ */
+ list_for_each_entry(scan, &rio_scans, node) {
+ if (scan->mport_id == mport_id) {
+ rc = -EBUSY;
+ goto err_out;
}
}
+
+ /*
+ * Allocate and initialize new scan registration node.
+ */
+ scan = kzalloc(sizeof(*scan), GFP_KERNEL);
+ if (!scan) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+
+ scan->mport_id = mport_id;
+ scan->ops = scan_ops;
+
+ /*
+ * Traverse the list of registered mports to attach this new scan.
+ *
+ * The new scan with matching mport ID overrides any previously attached
+ * scan assuming that old scan (if any) is the default one (based on the
+ * enumerator registration check above).
+ * If the new scan is the global one, it will be attached only to mports
+ * that do not have their own individual operations already attached.
+ */
+ list_for_each_entry(port, &rio_mports, node) {
+ if (port->id == mport_id) {
+ port->nscan = scan_ops;
+ break;
+ } else if (mport_id == RIO_MPORT_ANY && !port->nscan)
+ port->nscan = scan_ops;
+ }
+
+ list_add_tail(&scan->node, &rio_scans);
+
+err_out:
mutex_unlock(&rio_mport_list_lock);
return rc;
@@ -1447,30 +1690,83 @@ EXPORT_SYMBOL_GPL(rio_register_scan);
/**
* rio_unregister_scan - removes enumeration/discovery method from mport
* @mport_id: mport device ID for which fabric scan routine has to be
- * unregistered (RIO_MPORT_ANY = set for all available mports)
+ * unregistered (RIO_MPORT_ANY = apply to all mports that use
+ * the specified scan_ops)
+ * @scan_ops: enumeration/discovery operations structure
*
* Removes enumeration or discovery method assigned to the specified mport
- * device (or all available mports if RIO_MPORT_ANY is specified).
+ * device. If RIO_MPORT_ANY is specified, removes the specified operations from
+ * all mports that have them attached.
*/
-int rio_unregister_scan(int mport_id)
+int rio_unregister_scan(int mport_id, struct rio_scan *scan_ops)
{
struct rio_mport *port;
+ struct rio_scan_node *scan;
+
+ pr_debug("RIO: %s for mport_id=%d\n", __func__, mport_id);
+
+ if (mport_id != RIO_MPORT_ANY && mport_id >= RIO_MAX_MPORTS)
+ return -EINVAL;
mutex_lock(&rio_mport_list_lock);
- list_for_each_entry(port, &rio_mports, node) {
- if (port->id == mport_id || mport_id == RIO_MPORT_ANY) {
- if (port->nscan)
- port->nscan = NULL;
- if (mport_id != RIO_MPORT_ANY)
- break;
+
+ list_for_each_entry(port, &rio_mports, node)
+ if (port->id == mport_id ||
+ (mport_id == RIO_MPORT_ANY && port->nscan == scan_ops))
+ port->nscan = NULL;
+
+ list_for_each_entry(scan, &rio_scans, node) {
+ if (scan->mport_id == mport_id) {
+ list_del(&scan->node);
+ kfree(scan);
+ break;
}
}
+
mutex_unlock(&rio_mport_list_lock);
return 0;
}
EXPORT_SYMBOL_GPL(rio_unregister_scan);
+/**
+ * rio_mport_scan - execute enumeration/discovery on the specified mport
+ * @mport_id: number (ID) of mport device
+ */
+int rio_mport_scan(int mport_id)
+{
+ struct rio_mport *port = NULL;
+ int rc;
+
+ mutex_lock(&rio_mport_list_lock);
+ list_for_each_entry(port, &rio_mports, node) {
+ if (port->id == mport_id)
+ goto found;
+ }
+ mutex_unlock(&rio_mport_list_lock);
+ return -ENODEV;
+found:
+ if (!port->nscan) {
+ mutex_unlock(&rio_mport_list_lock);
+ return -EINVAL;
+ }
+
+ if (!try_module_get(port->nscan->owner)) {
+ mutex_unlock(&rio_mport_list_lock);
+ return -ENODEV;
+ }
+
+ mutex_unlock(&rio_mport_list_lock);
+
+ if (port->host_deviceid >= 0)
+ rc = port->nscan->enumerate(port, 0);
+ else
+ rc = port->nscan->discover(port, RIO_SCAN_ENUM_NO_WAIT);
+
+ module_put(port->nscan->owner);
+ return rc;
+}
+
static void rio_fixup_device(struct rio_dev *dev)
{
}
@@ -1499,7 +1795,10 @@ static void disc_work_handler(struct work_struct *_work)
work = container_of(_work, struct rio_disc_work, work);
pr_debug("RIO: discovery work for mport %d %s\n",
work->mport->id, work->mport->name);
- work->mport->nscan->discover(work->mport, 0);
+ if (try_module_get(work->mport->nscan->owner)) {
+ work->mport->nscan->discover(work->mport, 0);
+ module_put(work->mport->nscan->owner);
+ }
}
int rio_init_mports(void)
@@ -1518,8 +1817,10 @@ int rio_init_mports(void)
mutex_lock(&rio_mport_list_lock);
list_for_each_entry(port, &rio_mports, node) {
if (port->host_deviceid >= 0) {
- if (port->nscan)
+ if (port->nscan && try_module_get(port->nscan->owner)) {
port->nscan->enumerate(port, 0);
+ module_put(port->nscan->owner);
+ }
} else
n++;
}
@@ -1533,7 +1834,7 @@ int rio_init_mports(void)
* for each of them. If the code below fails to allocate needed
* resources, exit without error to keep results of enumeration
* process (if any).
- * TODO: Implement restart of dicovery process for all or
+ * TODO: Implement restart of discovery process for all or
* individual discovering mports.
*/
rio_wq = alloc_workqueue("riodisc", 0, 0);
@@ -1559,9 +1860,9 @@ int rio_init_mports(void)
n++;
}
}
- mutex_unlock(&rio_mport_list_lock);
flush_workqueue(rio_wq);
+ mutex_unlock(&rio_mport_list_lock);
pr_debug("RIO: destroy discovery workqueue\n");
destroy_workqueue(rio_wq);
kfree(work);
@@ -1572,26 +1873,19 @@ no_disc:
return 0;
}
-static int hdids[RIO_MAX_MPORTS + 1];
-
static int rio_get_hdid(int index)
{
- if (!hdids[0] || hdids[0] <= index || index >= RIO_MAX_MPORTS)
+ if (ids_num == 0 || ids_num <= index || index >= RIO_MAX_MPORTS)
return -1;
- return hdids[index + 1];
+ return hdid[index];
}
-static int rio_hdid_setup(char *str)
-{
- (void)get_options(str, ARRAY_SIZE(hdids), hdids);
- return 1;
-}
-
-__setup("riohdid=", rio_hdid_setup);
-
int rio_register_mport(struct rio_mport *port)
{
+ struct rio_scan_node *scan = NULL;
+ int res = 0;
+
if (next_portid >= RIO_MAX_MPORTS) {
pr_err("RIO: reached specified max number of mports\n");
return 1;
@@ -1600,11 +1894,38 @@ int rio_register_mport(struct rio_mport *port)
port->id = next_portid++;
port->host_deviceid = rio_get_hdid(port->id);
port->nscan = NULL;
+
+ dev_set_name(&port->dev, "rapidio%d", port->id);
+ port->dev.class = &rio_mport_class;
+
+ res = device_register(&port->dev);
+ if (res)
+ dev_err(&port->dev, "RIO: mport%d registration failed ERR=%d\n",
+ port->id, res);
+ else
+ dev_dbg(&port->dev, "RIO: mport%d registered\n", port->id);
+
mutex_lock(&rio_mport_list_lock);
list_add_tail(&port->node, &rio_mports);
+
+ /*
+ * Check if there are any registered enumeration/discovery operations
+ * that have to be attached to the added mport.
+ */
+ list_for_each_entry(scan, &rio_scans, node) {
+ if (port->id == scan->mport_id ||
+ scan->mport_id == RIO_MPORT_ANY) {
+ port->nscan = scan->ops;
+ if (port->id == scan->mport_id)
+ break;
+ }
+ }
mutex_unlock(&rio_mport_list_lock);
+
+ pr_debug("RIO: %s %s id=%d\n", __func__, port->name, port->id);
return 0;
}
+EXPORT_SYMBOL_GPL(rio_register_mport);
EXPORT_SYMBOL_GPL(rio_local_get_device_id);
EXPORT_SYMBOL_GPL(rio_get_device);
diff --git a/drivers/rapidio/rio.h b/drivers/rapidio/rio.h
index c14f864dea5..2d0550e08ea 100644
--- a/drivers/rapidio/rio.h
+++ b/drivers/rapidio/rio.h
@@ -28,52 +28,29 @@ extern u32 rio_mport_get_efb(struct rio_mport *port, int local, u16 destid,
extern int rio_mport_chk_dev_access(struct rio_mport *mport, u16 destid,
u8 hopcount);
extern int rio_create_sysfs_dev_files(struct rio_dev *rdev);
-extern int rio_std_route_add_entry(struct rio_mport *mport, u16 destid,
- u8 hopcount, u16 table, u16 route_destid,
- u8 route_port);
-extern int rio_std_route_get_entry(struct rio_mport *mport, u16 destid,
- u8 hopcount, u16 table, u16 route_destid,
- u8 *route_port);
-extern int rio_std_route_clr_table(struct rio_mport *mport, u16 destid,
- u8 hopcount, u16 table);
+extern int rio_lock_device(struct rio_mport *port, u16 destid,
+ u8 hopcount, int wait_ms);
+extern int rio_unlock_device(struct rio_mport *port, u16 destid, u8 hopcount);
+extern int rio_route_add_entry(struct rio_dev *rdev,
+ u16 table, u16 route_destid, u8 route_port, int lock);
+extern int rio_route_get_entry(struct rio_dev *rdev, u16 table,
+ u16 route_destid, u8 *route_port, 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 struct rio_dev *rio_get_comptag(u32 comp_tag, struct rio_dev *from);
extern int rio_add_device(struct rio_dev *rdev);
-extern void rio_switch_init(struct rio_dev *rdev, int do_enum);
extern int rio_enable_rx_tx_port(struct rio_mport *port, int local, u16 destid,
u8 hopcount, u8 port_num);
extern int rio_register_scan(int mport_id, struct rio_scan *scan_ops);
-extern int rio_unregister_scan(int mport_id);
+extern int rio_unregister_scan(int mport_id, struct rio_scan *scan_ops);
extern void rio_attach_device(struct rio_dev *rdev);
extern struct rio_mport *rio_find_mport(int mport_id);
+extern int rio_mport_scan(int mport_id);
/* Structures internal to the RIO core code */
-extern struct device_attribute rio_dev_attrs[];
-extern struct bus_attribute rio_bus_attrs[];
-
-extern struct rio_switch_ops __start_rio_switch_ops[];
-extern struct rio_switch_ops __end_rio_switch_ops[];
-
-/* Helpers internal to the RIO core code */
-#define DECLARE_RIO_SWITCH_SECTION(section, name, vid, did, init_hook) \
- static const struct rio_switch_ops __rio_switch_##name __used \
- __section(section) = { vid, did, init_hook };
-
-/**
- * DECLARE_RIO_SWITCH_INIT - Registers switch initialization routine
- * @vid: RIO vendor ID
- * @did: RIO device ID
- * @init_hook: Callback that performs switch-specific initialization
- *
- * Manipulating switch route tables and error management in RIO
- * is switch specific. This registers a switch by vendor and device ID with
- * initialization callback for setting up switch operations and (if required)
- * hardware initialization. A &struct rio_switch_ops is initialized with
- * pointer to the init routine and placed into a RIO-specific kernel section.
- */
-#define DECLARE_RIO_SWITCH_INIT(vid, did, init_hook) \
- DECLARE_RIO_SWITCH_SECTION(.rio_switch_ops, vid##did, \
- vid, did, init_hook)
+extern const struct attribute_group *rio_dev_groups[];
+extern const struct attribute_group *rio_bus_groups[];
+extern const struct attribute_group *rio_mport_groups[];
#define RIO_GET_DID(size, x) (size ? (x & 0xffff) : ((x & 0x00ff0000) >> 16))
#define RIO_SET_DID(size, x) (size ? (x & 0xffff) : ((x & 0x000000ff) << 16))
diff --git a/drivers/rapidio/switches/Kconfig b/drivers/rapidio/switches/Kconfig
index f47fee5d456..345841562f9 100644
--- a/drivers/rapidio/switches/Kconfig
+++ b/drivers/rapidio/switches/Kconfig
@@ -2,34 +2,23 @@
# RapidIO switches configuration
#
config RAPIDIO_TSI57X
- bool "IDT Tsi57x SRIO switches support"
- depends on RAPIDIO
+ tristate "IDT Tsi57x SRIO switches support"
---help---
Includes support for IDT Tsi57x family of serial RapidIO switches.
config RAPIDIO_CPS_XX
- bool "IDT CPS-xx SRIO switches support"
- depends on RAPIDIO
+ tristate "IDT CPS-xx SRIO switches support"
---help---
Includes support for IDT CPS-16/12/10/8 serial RapidIO switches.
config RAPIDIO_TSI568
- bool "Tsi568 SRIO switch support"
- depends on RAPIDIO
+ tristate "Tsi568 SRIO switch support"
default n
---help---
Includes support for IDT Tsi568 serial RapidIO switch.
config RAPIDIO_CPS_GEN2
- bool "IDT CPS Gen.2 SRIO switch support"
- depends on RAPIDIO
+ tristate "IDT CPS Gen.2 SRIO switch support"
default n
---help---
Includes support for ITD CPS Gen.2 serial RapidIO switches.
-
-config RAPIDIO_TSI500
- bool "Tsi500 Parallel RapidIO switch support"
- depends on RAPIDIO
- default n
- ---help---
- Includes support for IDT Tsi500 parallel RapidIO switch.
diff --git a/drivers/rapidio/switches/Makefile b/drivers/rapidio/switches/Makefile
index c4d3acc3c71..051cc6b3818 100644
--- a/drivers/rapidio/switches/Makefile
+++ b/drivers/rapidio/switches/Makefile
@@ -5,5 +5,4 @@
obj-$(CONFIG_RAPIDIO_TSI57X) += tsi57x.o
obj-$(CONFIG_RAPIDIO_CPS_XX) += idtcps.o
obj-$(CONFIG_RAPIDIO_TSI568) += tsi568.o
-obj-$(CONFIG_RAPIDIO_TSI500) += tsi500.o
obj-$(CONFIG_RAPIDIO_CPS_GEN2) += idt_gen2.o
diff --git a/drivers/rapidio/switches/idt_gen2.c b/drivers/rapidio/switches/idt_gen2.c
index 809b7a3336b..9f7fe21580b 100644
--- a/drivers/rapidio/switches/idt_gen2.c
+++ b/drivers/rapidio/switches/idt_gen2.c
@@ -11,10 +11,13 @@
*/
#include <linux/stat.h>
+#include <linux/module.h>
#include <linux/rio.h>
#include <linux/rio_drv.h>
#include <linux/rio_ids.h>
#include <linux/delay.h>
+
+#include <asm/page.h>
#include "../rio.h"
#define LOCAL_RTE_CONF_DESTID_SEL 0x010070
@@ -387,12 +390,12 @@ idtg2_show_errlog(struct device *dev, struct device_attribute *attr, char *buf)
static DEVICE_ATTR(errlog, S_IRUGO, idtg2_show_errlog, NULL);
-static int idtg2_sysfs(struct rio_dev *rdev, int create)
+static int idtg2_sysfs(struct rio_dev *rdev, bool create)
{
struct device *dev = &rdev->dev;
int err = 0;
- if (create == RIO_SW_SYSFS_CREATE) {
+ if (create) {
/* Initialize sysfs entries */
err = device_create_file(dev, &dev_attr_errlog);
if (err)
@@ -403,29 +406,90 @@ static int idtg2_sysfs(struct rio_dev *rdev, int create)
return err;
}
-static int idtg2_switch_init(struct rio_dev *rdev, int do_enum)
+static struct rio_switch_ops idtg2_switch_ops = {
+ .owner = THIS_MODULE,
+ .add_entry = idtg2_route_add_entry,
+ .get_entry = idtg2_route_get_entry,
+ .clr_table = idtg2_route_clr_table,
+ .set_domain = idtg2_set_domain,
+ .get_domain = idtg2_get_domain,
+ .em_init = idtg2_em_init,
+ .em_handle = idtg2_em_handler,
+};
+
+static int idtg2_probe(struct rio_dev *rdev, const struct rio_device_id *id)
{
pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
- rdev->rswitch->add_entry = idtg2_route_add_entry;
- rdev->rswitch->get_entry = idtg2_route_get_entry;
- rdev->rswitch->clr_table = idtg2_route_clr_table;
- rdev->rswitch->set_domain = idtg2_set_domain;
- rdev->rswitch->get_domain = idtg2_get_domain;
- rdev->rswitch->em_init = idtg2_em_init;
- rdev->rswitch->em_handle = idtg2_em_handler;
- rdev->rswitch->sw_sysfs = idtg2_sysfs;
-
- if (do_enum) {
+
+ spin_lock(&rdev->rswitch->lock);
+
+ if (rdev->rswitch->ops) {
+ spin_unlock(&rdev->rswitch->lock);
+ return -EINVAL;
+ }
+
+ rdev->rswitch->ops = &idtg2_switch_ops;
+
+ if (rdev->do_enum) {
/* Ensure that default routing is disabled on startup */
rio_write_config_32(rdev,
RIO_STD_RTE_DEFAULT_PORT, IDT_NO_ROUTE);
}
+ /* Create device-specific sysfs attributes */
+ idtg2_sysfs(rdev, true);
+
+ spin_unlock(&rdev->rswitch->lock);
return 0;
}
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1848, idtg2_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1616, idtg2_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTVPS1616, idtg2_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTSPS1616, idtg2_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS1432, idtg2_switch_init);
+static void idtg2_remove(struct rio_dev *rdev)
+{
+ pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+ spin_lock(&rdev->rswitch->lock);
+ if (rdev->rswitch->ops != &idtg2_switch_ops) {
+ spin_unlock(&rdev->rswitch->lock);
+ return;
+ }
+ rdev->rswitch->ops = NULL;
+
+ /* Remove device-specific sysfs attributes */
+ idtg2_sysfs(rdev, false);
+
+ spin_unlock(&rdev->rswitch->lock);
+}
+
+static struct rio_device_id idtg2_id_table[] = {
+ {RIO_DEVICE(RIO_DID_IDTCPS1848, RIO_VID_IDT)},
+ {RIO_DEVICE(RIO_DID_IDTCPS1616, RIO_VID_IDT)},
+ {RIO_DEVICE(RIO_DID_IDTVPS1616, RIO_VID_IDT)},
+ {RIO_DEVICE(RIO_DID_IDTSPS1616, RIO_VID_IDT)},
+ {RIO_DEVICE(RIO_DID_IDTCPS1432, RIO_VID_IDT)},
+ { 0, } /* terminate list */
+};
+
+static struct rio_driver idtg2_driver = {
+ .name = "idt_gen2",
+ .id_table = idtg2_id_table,
+ .probe = idtg2_probe,
+ .remove = idtg2_remove,
+};
+
+static int __init idtg2_init(void)
+{
+ return rio_register_driver(&idtg2_driver);
+}
+
+static void __exit idtg2_exit(void)
+{
+ pr_debug("RIO: %s\n", __func__);
+ rio_unregister_driver(&idtg2_driver);
+ pr_debug("RIO: %s done\n", __func__);
+}
+
+device_initcall(idtg2_init);
+module_exit(idtg2_exit);
+
+MODULE_DESCRIPTION("IDT CPS Gen.2 Serial RapidIO switch family driver");
+MODULE_AUTHOR("Integrated Device Technology, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rapidio/switches/idtcps.c b/drivers/rapidio/switches/idtcps.c
index d06ee2d44b4..7fbb60d3179 100644
--- a/drivers/rapidio/switches/idtcps.c
+++ b/drivers/rapidio/switches/idtcps.c
@@ -13,6 +13,7 @@
#include <linux/rio.h>
#include <linux/rio_drv.h>
#include <linux/rio_ids.h>
+#include <linux/module.h>
#include "../rio.h"
#define CPS_DEFAULT_ROUTE 0xde
@@ -118,18 +119,31 @@ idtcps_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
return 0;
}
-static int idtcps_switch_init(struct rio_dev *rdev, int do_enum)
+static struct rio_switch_ops idtcps_switch_ops = {
+ .owner = THIS_MODULE,
+ .add_entry = idtcps_route_add_entry,
+ .get_entry = idtcps_route_get_entry,
+ .clr_table = idtcps_route_clr_table,
+ .set_domain = idtcps_set_domain,
+ .get_domain = idtcps_get_domain,
+ .em_init = NULL,
+ .em_handle = NULL,
+};
+
+static int idtcps_probe(struct rio_dev *rdev, const struct rio_device_id *id)
{
pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
- rdev->rswitch->add_entry = idtcps_route_add_entry;
- rdev->rswitch->get_entry = idtcps_route_get_entry;
- rdev->rswitch->clr_table = idtcps_route_clr_table;
- rdev->rswitch->set_domain = idtcps_set_domain;
- rdev->rswitch->get_domain = idtcps_get_domain;
- rdev->rswitch->em_init = NULL;
- rdev->rswitch->em_handle = NULL;
-
- if (do_enum) {
+
+ spin_lock(&rdev->rswitch->lock);
+
+ if (rdev->rswitch->ops) {
+ spin_unlock(&rdev->rswitch->lock);
+ return -EINVAL;
+ }
+
+ rdev->rswitch->ops = &idtcps_switch_ops;
+
+ if (rdev->do_enum) {
/* set TVAL = ~50us */
rio_write_config_32(rdev,
rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8);
@@ -138,12 +152,52 @@ static int idtcps_switch_init(struct rio_dev *rdev, int do_enum)
RIO_STD_RTE_DEFAULT_PORT, CPS_NO_ROUTE);
}
+ spin_unlock(&rdev->rswitch->lock);
return 0;
}
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS6Q, idtcps_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS8, idtcps_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS10Q, idtcps_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS12, idtcps_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDTCPS16, idtcps_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_IDT, RIO_DID_IDT70K200, idtcps_switch_init);
+static void idtcps_remove(struct rio_dev *rdev)
+{
+ pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+ spin_lock(&rdev->rswitch->lock);
+ if (rdev->rswitch->ops != &idtcps_switch_ops) {
+ spin_unlock(&rdev->rswitch->lock);
+ return;
+ }
+ rdev->rswitch->ops = NULL;
+ spin_unlock(&rdev->rswitch->lock);
+}
+
+static struct rio_device_id idtcps_id_table[] = {
+ {RIO_DEVICE(RIO_DID_IDTCPS6Q, RIO_VID_IDT)},
+ {RIO_DEVICE(RIO_DID_IDTCPS8, RIO_VID_IDT)},
+ {RIO_DEVICE(RIO_DID_IDTCPS10Q, RIO_VID_IDT)},
+ {RIO_DEVICE(RIO_DID_IDTCPS12, RIO_VID_IDT)},
+ {RIO_DEVICE(RIO_DID_IDTCPS16, RIO_VID_IDT)},
+ {RIO_DEVICE(RIO_DID_IDT70K200, RIO_VID_IDT)},
+ { 0, } /* terminate list */
+};
+
+static struct rio_driver idtcps_driver = {
+ .name = "idtcps",
+ .id_table = idtcps_id_table,
+ .probe = idtcps_probe,
+ .remove = idtcps_remove,
+};
+
+static int __init idtcps_init(void)
+{
+ return rio_register_driver(&idtcps_driver);
+}
+
+static void __exit idtcps_exit(void)
+{
+ rio_unregister_driver(&idtcps_driver);
+}
+
+device_initcall(idtcps_init);
+module_exit(idtcps_exit);
+
+MODULE_DESCRIPTION("IDT CPS Gen.1 Serial RapidIO switch family driver");
+MODULE_AUTHOR("Integrated Device Technology, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rapidio/switches/tsi500.c b/drivers/rapidio/switches/tsi500.c
deleted file mode 100644
index 914eddd5aa4..00000000000
--- a/drivers/rapidio/switches/tsi500.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * RapidIO Tsi500 switch support
- *
- * Copyright 2009-2010 Integrated Device Technology, Inc.
- * Alexandre Bounine <alexandre.bounine@idt.com>
- * - Modified switch operations initialization.
- *
- * Copyright 2005 MontaVista Software, Inc.
- * Matt Porter <mporter@kernel.crashing.org>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- */
-
-#include <linux/rio.h>
-#include <linux/rio_drv.h>
-#include <linux/rio_ids.h>
-#include "../rio.h"
-
-static int
-tsi500_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, u16 table, u16 route_destid, u8 route_port)
-{
- int i;
- u32 offset = 0x10000 + 0xa00 + ((route_destid / 2)&~0x3);
- u32 result;
-
- if (table == 0xff) {
- rio_mport_read_config_32(mport, destid, hopcount, offset, &result);
- result &= ~(0xf << (4*(route_destid & 0x7)));
- for (i=0;i<4;i++)
- rio_mport_write_config_32(mport, destid, hopcount, offset + (0x20000*i), result | (route_port << (4*(route_destid & 0x7))));
- }
- else {
- rio_mport_read_config_32(mport, destid, hopcount, offset + (0x20000*table), &result);
- result &= ~(0xf << (4*(route_destid & 0x7)));
- rio_mport_write_config_32(mport, destid, hopcount, offset + (0x20000*table), result | (route_port << (4*(route_destid & 0x7))));
- }
-
- return 0;
-}
-
-static int
-tsi500_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, u16 table, u16 route_destid, u8 *route_port)
-{
- int ret = 0;
- u32 offset = 0x10000 + 0xa00 + ((route_destid / 2)&~0x3);
- u32 result;
-
- if (table == 0xff)
- rio_mport_read_config_32(mport, destid, hopcount, offset, &result);
- else
- rio_mport_read_config_32(mport, destid, hopcount, offset + (0x20000*table), &result);
-
- result &= 0xf << (4*(route_destid & 0x7));
- *route_port = result >> (4*(route_destid & 0x7));
- if (*route_port > 3)
- ret = -1;
-
- return ret;
-}
-
-static int tsi500_switch_init(struct rio_dev *rdev, int do_enum)
-{
- pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
- rdev->rswitch->add_entry = tsi500_route_add_entry;
- rdev->rswitch->get_entry = tsi500_route_get_entry;
- rdev->rswitch->clr_table = NULL;
- rdev->rswitch->set_domain = NULL;
- rdev->rswitch->get_domain = NULL;
- rdev->rswitch->em_init = NULL;
- rdev->rswitch->em_handle = NULL;
-
- return 0;
-}
-
-DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI500, tsi500_switch_init);
diff --git a/drivers/rapidio/switches/tsi568.c b/drivers/rapidio/switches/tsi568.c
index 3994c00aa01..8a43561b9d1 100644
--- a/drivers/rapidio/switches/tsi568.c
+++ b/drivers/rapidio/switches/tsi568.c
@@ -19,6 +19,7 @@
#include <linux/rio_drv.h>
#include <linux/rio_ids.h>
#include <linux/delay.h>
+#include <linux/module.h>
#include "../rio.h"
/* Global (broadcast) route registers */
@@ -129,18 +130,70 @@ tsi568_em_init(struct rio_dev *rdev)
return 0;
}
-static int tsi568_switch_init(struct rio_dev *rdev, int do_enum)
+static struct rio_switch_ops tsi568_switch_ops = {
+ .owner = THIS_MODULE,
+ .add_entry = tsi568_route_add_entry,
+ .get_entry = tsi568_route_get_entry,
+ .clr_table = tsi568_route_clr_table,
+ .set_domain = NULL,
+ .get_domain = NULL,
+ .em_init = tsi568_em_init,
+ .em_handle = NULL,
+};
+
+static int tsi568_probe(struct rio_dev *rdev, const struct rio_device_id *id)
{
pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
- rdev->rswitch->add_entry = tsi568_route_add_entry;
- rdev->rswitch->get_entry = tsi568_route_get_entry;
- rdev->rswitch->clr_table = tsi568_route_clr_table;
- rdev->rswitch->set_domain = NULL;
- rdev->rswitch->get_domain = NULL;
- rdev->rswitch->em_init = tsi568_em_init;
- rdev->rswitch->em_handle = NULL;
+ spin_lock(&rdev->rswitch->lock);
+
+ if (rdev->rswitch->ops) {
+ spin_unlock(&rdev->rswitch->lock);
+ return -EINVAL;
+ }
+
+ rdev->rswitch->ops = &tsi568_switch_ops;
+ spin_unlock(&rdev->rswitch->lock);
return 0;
}
-DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI568, tsi568_switch_init);
+static void tsi568_remove(struct rio_dev *rdev)
+{
+ pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+ spin_lock(&rdev->rswitch->lock);
+ if (rdev->rswitch->ops != &tsi568_switch_ops) {
+ spin_unlock(&rdev->rswitch->lock);
+ return;
+ }
+ rdev->rswitch->ops = NULL;
+ spin_unlock(&rdev->rswitch->lock);
+}
+
+static struct rio_device_id tsi568_id_table[] = {
+ {RIO_DEVICE(RIO_DID_TSI568, RIO_VID_TUNDRA)},
+ { 0, } /* terminate list */
+};
+
+static struct rio_driver tsi568_driver = {
+ .name = "tsi568",
+ .id_table = tsi568_id_table,
+ .probe = tsi568_probe,
+ .remove = tsi568_remove,
+};
+
+static int __init tsi568_init(void)
+{
+ return rio_register_driver(&tsi568_driver);
+}
+
+static void __exit tsi568_exit(void)
+{
+ rio_unregister_driver(&tsi568_driver);
+}
+
+device_initcall(tsi568_init);
+module_exit(tsi568_exit);
+
+MODULE_DESCRIPTION("IDT Tsi568 Serial RapidIO switch driver");
+MODULE_AUTHOR("Integrated Device Technology, Inc.");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rapidio/switches/tsi57x.c b/drivers/rapidio/switches/tsi57x.c
index db8b8028988..42c8b014fe1 100644
--- a/drivers/rapidio/switches/tsi57x.c
+++ b/drivers/rapidio/switches/tsi57x.c
@@ -19,6 +19,7 @@
#include <linux/rio_drv.h>
#include <linux/rio_ids.h>
#include <linux/delay.h>
+#include <linux/module.h>
#include "../rio.h"
/* Global (broadcast) route registers */
@@ -292,27 +293,79 @@ exit_es:
return 0;
}
-static int tsi57x_switch_init(struct rio_dev *rdev, int do_enum)
+static struct rio_switch_ops tsi57x_switch_ops = {
+ .owner = THIS_MODULE,
+ .add_entry = tsi57x_route_add_entry,
+ .get_entry = tsi57x_route_get_entry,
+ .clr_table = tsi57x_route_clr_table,
+ .set_domain = tsi57x_set_domain,
+ .get_domain = tsi57x_get_domain,
+ .em_init = tsi57x_em_init,
+ .em_handle = tsi57x_em_handler,
+};
+
+static int tsi57x_probe(struct rio_dev *rdev, const struct rio_device_id *id)
{
pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
- rdev->rswitch->add_entry = tsi57x_route_add_entry;
- rdev->rswitch->get_entry = tsi57x_route_get_entry;
- rdev->rswitch->clr_table = tsi57x_route_clr_table;
- rdev->rswitch->set_domain = tsi57x_set_domain;
- rdev->rswitch->get_domain = tsi57x_get_domain;
- rdev->rswitch->em_init = tsi57x_em_init;
- rdev->rswitch->em_handle = tsi57x_em_handler;
-
- if (do_enum) {
+
+ spin_lock(&rdev->rswitch->lock);
+
+ if (rdev->rswitch->ops) {
+ spin_unlock(&rdev->rswitch->lock);
+ return -EINVAL;
+ }
+ rdev->rswitch->ops = &tsi57x_switch_ops;
+
+ if (rdev->do_enum) {
/* Ensure that default routing is disabled on startup */
rio_write_config_32(rdev, RIO_STD_RTE_DEFAULT_PORT,
RIO_INVALID_ROUTE);
}
+ spin_unlock(&rdev->rswitch->lock);
return 0;
}
-DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI572, tsi57x_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI574, tsi57x_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI577, tsi57x_switch_init);
-DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI578, tsi57x_switch_init);
+static void tsi57x_remove(struct rio_dev *rdev)
+{
+ pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
+ spin_lock(&rdev->rswitch->lock);
+ if (rdev->rswitch->ops != &tsi57x_switch_ops) {
+ spin_unlock(&rdev->rswitch->lock);
+ return;
+ }
+ rdev->rswitch->ops = NULL;
+ spin_unlock(&rdev->rswitch->lock);
+}
+
+static struct rio_device_id tsi57x_id_table[] = {
+ {RIO_DEVICE(RIO_DID_TSI572, RIO_VID_TUNDRA)},
+ {RIO_DEVICE(RIO_DID_TSI574, RIO_VID_TUNDRA)},
+ {RIO_DEVICE(RIO_DID_TSI577, RIO_VID_TUNDRA)},
+ {RIO_DEVICE(RIO_DID_TSI578, RIO_VID_TUNDRA)},
+ { 0, } /* terminate list */
+};
+
+static struct rio_driver tsi57x_driver = {
+ .name = "tsi57x",
+ .id_table = tsi57x_id_table,
+ .probe = tsi57x_probe,
+ .remove = tsi57x_remove,
+};
+
+static int __init tsi57x_init(void)
+{
+ return rio_register_driver(&tsi57x_driver);
+}
+
+static void __exit tsi57x_exit(void)
+{
+ rio_unregister_driver(&tsi57x_driver);
+}
+
+device_initcall(tsi57x_init);
+module_exit(tsi57x_exit);
+
+MODULE_DESCRIPTION("IDT Tsi57x Serial RapidIO switch family driver");
+MODULE_AUTHOR("Integrated Device Technology, Inc.");
+MODULE_LICENSE("GPL");