bus: fsl-mc: add the fsl_mc_get_endpoint function
authorIoana Ciornei <ioana.ciornei@nxp.com>
Wed, 30 Oct 2019 23:18:29 +0000 (01:18 +0200)
committerDavid S. Miller <davem@davemloft.net>
Thu, 31 Oct 2019 21:19:45 +0000 (14:19 -0700)
Using the newly added fsl_mc_get_endpoint function a fsl-mc driver can
find its associated endpoint (another object at the other link of a MC
firmware link).

The API will be used in the following patch in order to discover the
connected DPMAC object of a DPNI.

Also, the fsl_mc_device_lookup function is made available to the entire
fsl-mc bus driver and not just for the dprc driver.

Signed-off-by: Ioana Ciornei <ioana.ciornei@nxp.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/bus/fsl-mc/dprc-driver.c
drivers/bus/fsl-mc/dprc.c
drivers/bus/fsl-mc/fsl-mc-bus.c
drivers/bus/fsl-mc/fsl-mc-private.h
include/linux/fsl/mc.h

index 52c7e15143d6d6e62087f8ad4db6fcdca3d1e4d9..c8b1c3842c1ad26f5412e95f2ff5418fc0811bc6 100644 (file)
@@ -104,10 +104,8 @@ static int __fsl_mc_device_match(struct device *dev, void *data)
        return fsl_mc_device_match(mc_dev, obj_desc);
 }
 
-static struct fsl_mc_device *fsl_mc_device_lookup(struct fsl_mc_obj_desc
-                                                               *obj_desc,
-                                                 struct fsl_mc_device
-                                                               *mc_bus_dev)
+struct fsl_mc_device *fsl_mc_device_lookup(struct fsl_mc_obj_desc *obj_desc,
+                                          struct fsl_mc_device *mc_bus_dev)
 {
        struct device *dev;
 
index 0fe3f52ae0de8fe3dc6799d51d8ce598ab9b740a..602f030d84eb87b4fc597d7e0e4b8c3c41e31778 100644 (file)
@@ -554,3 +554,56 @@ int dprc_get_container_id(struct fsl_mc_io *mc_io,
 
        return 0;
 }
+
+/**
+ * dprc_get_connection() - Get connected endpoint and link status if connection
+ *                     exists.
+ * @mc_io:     Pointer to MC portal's I/O object
+ * @cmd_flags: Command flags; one or more of 'MC_CMD_FLAG_'
+ * @token:     Token of DPRC object
+ * @endpoint1: Endpoint 1 configuration parameters
+ * @endpoint2: Returned endpoint 2 configuration parameters
+ * @state:     Returned link state:
+ *             1 - link is up;
+ *             0 - link is down;
+ *             -1 - no connection (endpoint2 information is irrelevant)
+ *
+ * Return:     '0' on Success; -ENOTCONN if connection does not exist.
+ */
+int dprc_get_connection(struct fsl_mc_io *mc_io,
+                       u32 cmd_flags,
+                       u16 token,
+                       const struct dprc_endpoint *endpoint1,
+                       struct dprc_endpoint *endpoint2,
+                       int *state)
+{
+       struct dprc_cmd_get_connection *cmd_params;
+       struct dprc_rsp_get_connection *rsp_params;
+       struct fsl_mc_command cmd = { 0 };
+       int err, i;
+
+       /* prepare command */
+       cmd.header = mc_encode_cmd_header(DPRC_CMDID_GET_CONNECTION,
+                                         cmd_flags,
+                                         token);
+       cmd_params = (struct dprc_cmd_get_connection *)cmd.params;
+       cmd_params->ep1_id = cpu_to_le32(endpoint1->id);
+       cmd_params->ep1_interface_id = cpu_to_le16(endpoint1->if_id);
+       for (i = 0; i < 16; i++)
+               cmd_params->ep1_type[i] = endpoint1->type[i];
+
+       /* send command to mc */
+       err = mc_send_command(mc_io, &cmd);
+       if (err)
+               return -ENOTCONN;
+
+       /* retrieve response parameters */
+       rsp_params = (struct dprc_rsp_get_connection *)cmd.params;
+       endpoint2->id = le32_to_cpu(rsp_params->ep2_id);
+       endpoint2->if_id = le16_to_cpu(rsp_params->ep2_interface_id);
+       *state = le32_to_cpu(rsp_params->state);
+       for (i = 0; i < 16; i++)
+               endpoint2->type[i] = rsp_params->ep2_type[i];
+
+       return 0;
+}
index bb3c2fc7c5baf2c2502653d519cfa4fbe8a0d36e..a07cc19becdbadca7cfd3ccb4fc9d0c92c6aa917 100644 (file)
@@ -712,6 +712,39 @@ void fsl_mc_device_remove(struct fsl_mc_device *mc_dev)
 }
 EXPORT_SYMBOL_GPL(fsl_mc_device_remove);
 
+struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev)
+{
+       struct fsl_mc_device *mc_bus_dev, *endpoint;
+       struct fsl_mc_obj_desc endpoint_desc = { 0 };
+       struct dprc_endpoint endpoint1 = { 0 };
+       struct dprc_endpoint endpoint2 = { 0 };
+       int state, err;
+
+       mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent);
+       strcpy(endpoint1.type, mc_dev->obj_desc.type);
+       endpoint1.id = mc_dev->obj_desc.id;
+
+       err = dprc_get_connection(mc_bus_dev->mc_io, 0,
+                                 mc_bus_dev->mc_handle,
+                                 &endpoint1, &endpoint2,
+                                 &state);
+
+       if (err == -ENOTCONN || state == -1)
+               return ERR_PTR(-ENOTCONN);
+
+       if (err < 0) {
+               dev_err(&mc_bus_dev->dev, "dprc_get_connection() = %d\n", err);
+               return ERR_PTR(err);
+       }
+
+       strcpy(endpoint_desc.type, endpoint2.type);
+       endpoint_desc.id = endpoint2.id;
+       endpoint = fsl_mc_device_lookup(&endpoint_desc, mc_bus_dev);
+
+       return endpoint;
+}
+EXPORT_SYMBOL_GPL(fsl_mc_get_endpoint);
+
 static int parse_mc_ranges(struct device *dev,
                           int *paddr_cells,
                           int *mc_addr_cells,
index 020fcc04ec8bcb16d321d8a7f194b0947050d674..21ca8c756ee7748ccca749ec38f6082fefd69791 100644 (file)
@@ -105,6 +105,8 @@ int dpmcp_reset(struct fsl_mc_io *mc_io,
 #define DPRC_CMDID_GET_OBJ_REG_V2               DPRC_CMD_V2(0x15E)
 #define DPRC_CMDID_SET_OBJ_IRQ                  DPRC_CMD(0x15F)
 
+#define DPRC_CMDID_GET_CONNECTION               DPRC_CMD(0x16C)
+
 struct dprc_cmd_open {
        __le32 container_id;
 };
@@ -228,6 +230,22 @@ struct dprc_cmd_set_obj_irq {
        u8 obj_type[16];
 };
 
+struct dprc_cmd_get_connection {
+       __le32 ep1_id;
+       __le16 ep1_interface_id;
+       u8 pad[2];
+       u8 ep1_type[16];
+};
+
+struct dprc_rsp_get_connection {
+       __le64 pad[3];
+       __le32 ep2_id;
+       __le16 ep2_interface_id;
+       __le16 pad1;
+       u8 ep2_type[16];
+       __le32 state;
+};
+
 /*
  * DPRC API for managing and querying DPAA resources
  */
@@ -392,6 +410,27 @@ int dprc_get_container_id(struct fsl_mc_io *mc_io,
                          u32 cmd_flags,
                          int *container_id);
 
+/**
+ * struct dprc_endpoint - Endpoint description for link connect/disconnect
+ *                     operations
+ * @type:      Endpoint object type: NULL terminated string
+ * @id:                Endpoint object ID
+ * @if_id:     Interface ID; should be set for endpoints with multiple
+ *             interfaces ("dpsw", "dpdmux"); for others, always set to 0
+ */
+struct dprc_endpoint {
+       char type[16];
+       int id;
+       u16 if_id;
+};
+
+int dprc_get_connection(struct fsl_mc_io *mc_io,
+                       u32 cmd_flags,
+                       u16 token,
+                       const struct dprc_endpoint *endpoint1,
+                       struct dprc_endpoint *endpoint2,
+                       int *state);
+
 /*
  * Data Path Buffer Pool (DPBP) API
  */
@@ -574,4 +613,7 @@ void fsl_destroy_mc_io(struct fsl_mc_io *mc_io);
 
 bool fsl_mc_is_root_dprc(struct device *dev);
 
+struct fsl_mc_device *fsl_mc_device_lookup(struct fsl_mc_obj_desc *obj_desc,
+                                          struct fsl_mc_device *mc_bus_dev);
+
 #endif /* _FSL_MC_PRIVATE_H_ */
index 975553a9f75d9490df6ad2c827790c324388dbb0..54d9436600c7dfda91706b44d8c7426dad436581 100644 (file)
@@ -403,6 +403,8 @@ int __must_check fsl_mc_allocate_irqs(struct fsl_mc_device *mc_dev);
 
 void fsl_mc_free_irqs(struct fsl_mc_device *mc_dev);
 
+struct fsl_mc_device *fsl_mc_get_endpoint(struct fsl_mc_device *mc_dev);
+
 extern struct bus_type fsl_mc_bus_type;
 
 extern struct device_type fsl_mc_bus_dprc_type;