Skip to content

Commit

Permalink
rapidio: add global inbound port write interfaces
Browse files Browse the repository at this point in the history
Add new Port Write handler registration interfaces that attach PW
handlers to local mport device objects.  This is different from old
interface that attaches PW callback to individual RapidIO device.  The
new interfaces are intended for use for common event handling (e.g.
hot-plug notifications) while the old interface is available for
individual device drivers.

This patch is based on patch proposed by Andre van Herk but preserves
existing per-device interface and adds lock protection for list
handling.

Signed-off-by: Alexandre Bounine <[email protected]>
Cc: Matt Porter <[email protected]>
Cc: Aurelien Jacquiot <[email protected]>
Cc: Andre van Herk <[email protected]>
Cc: Stephen Rothwell <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Alexandre Bounine authored and torvalds committed Mar 22, 2016
1 parent b6cb95e commit 9a0b062
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 51 deletions.
1 change: 1 addition & 0 deletions arch/powerpc/sysdev/fsl_rio.c
Original file line number Diff line number Diff line change
Expand Up @@ -726,6 +726,7 @@ int fsl_rio_setup(struct platform_device *dev)
fsl_rio_inbound_mem_init(priv);

dbell->mport[i] = port;
pw->mport[i] = port;

if (rio_register_mport(port)) {
release_resource(&port->iores);
Expand Down
1 change: 1 addition & 0 deletions arch/powerpc/sysdev/fsl_rio.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ struct fsl_rio_dbell {
};

struct fsl_rio_pw {
struct rio_mport *mport[MAX_PORT_NUM];
struct device *dev;
struct rio_pw_regs __iomem *pw_regs;
struct rio_port_write_msg port_write_msg;
Expand Down
16 changes: 10 additions & 6 deletions arch/powerpc/sysdev/fsl_rmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -481,30 +481,34 @@ fsl_rio_port_write_handler(int irq, void *dev_instance)
static void fsl_pw_dpc(struct work_struct *work)
{
struct fsl_rio_pw *pw = container_of(work, struct fsl_rio_pw, pw_work);
u32 msg_buffer[RIO_PW_MSG_SIZE/sizeof(u32)];
union rio_pw_msg msg_buffer;
int i;

/*
* Process port-write messages
*/
while (kfifo_out_spinlocked(&pw->pw_fifo, (unsigned char *)msg_buffer,
while (kfifo_out_spinlocked(&pw->pw_fifo, (unsigned char *)&msg_buffer,
RIO_PW_MSG_SIZE, &pw->pw_fifo_lock)) {
/* Process one message */
#ifdef DEBUG_PW
{
u32 i;
pr_debug("%s : Port-Write Message:", __func__);
for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32); i++) {
if ((i%4) == 0)
pr_debug("\n0x%02x: 0x%08x", i*4,
msg_buffer[i]);
msg_buffer.raw[i]);
else
pr_debug(" 0x%08x", msg_buffer[i]);
pr_debug(" 0x%08x", msg_buffer.raw[i]);
}
pr_debug("\n");
}
#endif
/* Pass the port-write message to RIO core for processing */
rio_inb_pwrite_handler((union rio_pw_msg *)msg_buffer);
for (i = 0; i < MAX_PORT_NUM; i++) {
if (pw->mport[i])
rio_inb_pwrite_handler(pw->mport[i],
&msg_buffer);
}
}
}

Expand Down
24 changes: 4 additions & 20 deletions drivers/rapidio/devices/tsi721.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@

#include "tsi721.h"

#define DEBUG_PW /* Inbound Port-Write debugging */

static void tsi721_omsg_handler(struct tsi721_device *priv, int ch);
static void tsi721_imsg_handler(struct tsi721_device *priv, int ch);

Expand Down Expand Up @@ -282,30 +280,15 @@ static void tsi721_pw_dpc(struct work_struct *work)
{
struct tsi721_device *priv = container_of(work, struct tsi721_device,
pw_work);
u32 msg_buffer[RIO_PW_MSG_SIZE/sizeof(u32)]; /* Use full size PW message
buffer for RIO layer */
union rio_pw_msg pwmsg;

/*
* Process port-write messages
*/
while (kfifo_out_spinlocked(&priv->pw_fifo, (unsigned char *)msg_buffer,
while (kfifo_out_spinlocked(&priv->pw_fifo, (unsigned char *)&pwmsg,
TSI721_RIO_PW_MSG_SIZE, &priv->pw_fifo_lock)) {
/* Process one message */
#ifdef DEBUG_PW
{
u32 i;
pr_debug("%s : Port-Write Message:", __func__);
for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32); ) {
pr_debug("0x%02x: %08x %08x %08x %08x", i*4,
msg_buffer[i], msg_buffer[i + 1],
msg_buffer[i + 2], msg_buffer[i + 3]);
i += 4;
}
pr_debug("\n");
}
#endif
/* Pass the port-write message to RIO core for processing */
rio_inb_pwrite_handler((union rio_pw_msg *)msg_buffer);
rio_inb_pwrite_handler(&priv->mport, &pwmsg);
}
}

Expand Down Expand Up @@ -2702,6 +2685,7 @@ static void tsi721_remove(struct pci_dev *pdev)

tsi721_disable_ints(priv);
tsi721_free_irq(priv);
flush_scheduled_work();
rio_unregister_mport(&priv->mport);

tsi721_unregister_dma(priv);
Expand Down
142 changes: 118 additions & 24 deletions drivers/rapidio/rio.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,20 @@

#include "rio.h"

/*
* struct rio_pwrite - RIO portwrite event
* @node: Node in list of doorbell events
* @pwcback: Doorbell event callback
* @context: Handler specific context to pass on event
*/
struct rio_pwrite {
struct list_head node;

int (*pwcback)(struct rio_mport *mport, void *context,
union rio_pw_msg *msg, int step);
void *context;
};

MODULE_DESCRIPTION("RapidIO Subsystem Core");
MODULE_AUTHOR("Matt Porter <[email protected]>");
MODULE_AUTHOR("Alexandre Bounine <[email protected]>");
Expand Down Expand Up @@ -514,7 +528,71 @@ int rio_release_outb_dbell(struct rio_dev *rdev, struct resource *res)
}

/**
* rio_request_inb_pwrite - request inbound port-write message service
* rio_add_mport_pw_handler - add port-write message handler into the list
* of mport specific pw handlers
* @mport: RIO master port to bind the portwrite callback
* @context: Handler specific context to pass on event
* @pwcback: Callback to execute when portwrite is received
*
* Returns 0 if the request has been satisfied.
*/
int rio_add_mport_pw_handler(struct rio_mport *mport, void *context,
int (*pwcback)(struct rio_mport *mport,
void *context, union rio_pw_msg *msg, int step))
{
int rc = 0;
struct rio_pwrite *pwrite;

pwrite = kzalloc(sizeof(struct rio_pwrite), GFP_KERNEL);
if (!pwrite) {
rc = -ENOMEM;
goto out;
}

pwrite->pwcback = pwcback;
pwrite->context = context;
mutex_lock(&mport->lock);
list_add_tail(&pwrite->node, &mport->pwrites);
mutex_unlock(&mport->lock);
out:
return rc;
}
EXPORT_SYMBOL_GPL(rio_add_mport_pw_handler);

/**
* rio_del_mport_pw_handler - remove port-write message handler from the list
* of mport specific pw handlers
* @mport: RIO master port to bind the portwrite callback
* @context: Registered handler specific context to pass on event
* @pwcback: Registered callback function
*
* Returns 0 if the request has been satisfied.
*/
int rio_del_mport_pw_handler(struct rio_mport *mport, void *context,
int (*pwcback)(struct rio_mport *mport,
void *context, union rio_pw_msg *msg, int step))
{
int rc = -EINVAL;
struct rio_pwrite *pwrite;

mutex_lock(&mport->lock);
list_for_each_entry(pwrite, &mport->pwrites, node) {
if (pwrite->pwcback == pwcback && pwrite->context == context) {
list_del(&pwrite->node);
kfree(pwrite);
rc = 0;
break;
}
}
mutex_unlock(&mport->lock);

return rc;
}
EXPORT_SYMBOL_GPL(rio_del_mport_pw_handler);

/**
* rio_request_inb_pwrite - request inbound port-write message service for
* specific RapidIO device
* @rdev: RIO device to which register inbound port-write callback routine
* @pwcback: Callback routine to execute when port-write is received
*
Expand All @@ -539,6 +617,7 @@ EXPORT_SYMBOL_GPL(rio_request_inb_pwrite);

/**
* rio_release_inb_pwrite - release inbound port-write message service
* associated with specific RapidIO device
* @rdev: RIO device which registered for inbound port-write callback
*
* Removes callback from the rio_dev structure. Returns 0 if the request
Expand Down Expand Up @@ -1002,52 +1081,66 @@ static int rio_clr_err_stopped(struct rio_dev *rdev, u32 pnum, u32 err_status)
}

/**
* rio_inb_pwrite_handler - process inbound port-write message
* rio_inb_pwrite_handler - inbound port-write message handler
* @mport: mport device associated with port-write
* @pw_msg: pointer to inbound port-write message
*
* Processes an inbound port-write message. Returns 0 if the request
* has been satisfied.
*/
int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg)
int rio_inb_pwrite_handler(struct rio_mport *mport, union rio_pw_msg *pw_msg)
{
struct rio_dev *rdev;
u32 err_status, em_perrdet, em_ltlerrdet;
int rc, portnum;

rdev = rio_get_comptag((pw_msg->em.comptag & RIO_CTAG_UDEVID), NULL);
if (rdev == NULL) {
/* Device removed or enumeration error */
pr_debug("RIO: %s No matching device for CTag 0x%08x\n",
__func__, pw_msg->em.comptag);
return -EIO;
}

pr_debug("RIO: Port-Write message from %s\n", rio_name(rdev));
struct rio_pwrite *pwrite;

#ifdef DEBUG_PW
{
u32 i;
for (i = 0; i < RIO_PW_MSG_SIZE/sizeof(u32);) {
u32 i;

pr_debug("%s: PW to mport_%d:\n", __func__, mport->id);
for (i = 0; i < RIO_PW_MSG_SIZE / sizeof(u32); i = i + 4) {
pr_debug("0x%02x: %08x %08x %08x %08x\n",
i*4, pw_msg->raw[i], pw_msg->raw[i + 1],
pw_msg->raw[i + 2], pw_msg->raw[i + 3]);
i += 4;
}
i * 4, pw_msg->raw[i], pw_msg->raw[i + 1],
pw_msg->raw[i + 2], pw_msg->raw[i + 3]);
}
}
#endif

/* Call an external service function (if such is registered
* for this device). This may be the service for endpoints that send
* device-specific port-write messages. End-point messages expected
* to be handled completely by EP specific device driver.
rdev = rio_get_comptag((pw_msg->em.comptag & RIO_CTAG_UDEVID), NULL);
if (rdev) {
pr_debug("RIO: Port-Write message from %s\n", rio_name(rdev));
} else {
pr_debug("RIO: %s No matching device for CTag 0x%08x\n",
__func__, pw_msg->em.comptag);
}

/* Call a device-specific handler (if it is registered for the device).
* This may be the service for endpoints that send device-specific
* port-write messages. End-point messages expected to be handled
* completely by EP specific device driver.
* For switches rc==0 signals that no standard processing required.
*/
if (rdev->pwcback != NULL) {
if (rdev && rdev->pwcback) {
rc = rdev->pwcback(rdev, pw_msg, 0);
if (rc == 0)
return 0;
}

mutex_lock(&mport->lock);
list_for_each_entry(pwrite, &mport->pwrites, node)
pwrite->pwcback(mport, pwrite->context, pw_msg, 0);
mutex_unlock(&mport->lock);

if (!rdev)
return 0;

/*
* FIXME: The code below stays as it was before for now until we decide
* how to do default PW handling in combination with per-mport callbacks
*/

portnum = pw_msg->em.is_port & 0xFF;

/* Check if device and route to it are functional:
Expand Down Expand Up @@ -2060,6 +2153,7 @@ int rio_mport_initialize(struct rio_mport *mport)
mport->nscan = NULL;
mutex_init(&mport->lock);
mport->pwe_refcnt = 0;
INIT_LIST_HEAD(&mport->pwrites);

return 0;
}
Expand Down
2 changes: 2 additions & 0 deletions include/linux/rio.h
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ enum rio_phy_type {
/**
* struct rio_mport - RIO master port info
* @dbells: List of doorbell events
* @pwrites: List of portwrite 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
Expand All @@ -270,6 +271,7 @@ enum rio_phy_type {
*/
struct rio_mport {
struct list_head dbells; /* list of doorbell events */
struct list_head pwrites; /* list of portwrite 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 */
Expand Down
9 changes: 8 additions & 1 deletion include/linux/rio_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -374,7 +374,14 @@ extern void rio_unmap_inb_region(struct rio_mport *mport, dma_addr_t lstart);
extern int rio_request_inb_pwrite(struct rio_dev *,
int (*)(struct rio_dev *, union rio_pw_msg*, int));
extern int rio_release_inb_pwrite(struct rio_dev *);
extern int rio_inb_pwrite_handler(union rio_pw_msg *pw_msg);
extern int rio_add_mport_pw_handler(struct rio_mport *mport, void *dev_id,
int (*pwcback)(struct rio_mport *mport, void *dev_id,
union rio_pw_msg *msg, int step));
extern int rio_del_mport_pw_handler(struct rio_mport *mport, void *dev_id,
int (*pwcback)(struct rio_mport *mport, void *dev_id,
union rio_pw_msg *msg, int step));
extern int rio_inb_pwrite_handler(struct rio_mport *mport,
union rio_pw_msg *pw_msg);
extern void rio_pw_enable(struct rio_mport *mport, int enable);

/* LDM support */
Expand Down

0 comments on commit 9a0b062

Please sign in to comment.