Merge tag 'soc-fsl-next-v5.3-2' of git://git.kernel.org/pub/scm/linux/kernel/git...
[sfrench/cifs-2.6.git] / drivers / soc / fsl / qe / qe.c
index 62c6ba17991ad614d787d0ff57d9f39f53341982..ba38c4bb2a88fa938d2e7bcf413828480cfa153e 100644 (file)
@@ -10,6 +10,7 @@
  * General Purpose functions for the global management of the
  * QUICC Engine (QE).
  */
+#include <linux/bitmap.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/kernel.h>
@@ -39,29 +40,32 @@ static DEFINE_SPINLOCK(qe_lock);
 DEFINE_SPINLOCK(cmxgcr_lock);
 EXPORT_SYMBOL(cmxgcr_lock);
 
-/* QE snum state */
-enum qe_snum_state {
-       QE_SNUM_STATE_USED,
-       QE_SNUM_STATE_FREE
-};
-
-/* QE snum */
-struct qe_snum {
-       u8 num;
-       enum qe_snum_state state;
-};
-
 /* We allocate this here because it is used almost exclusively for
  * the communication processor devices.
  */
 struct qe_immap __iomem *qe_immr;
 EXPORT_SYMBOL(qe_immr);
 
-static struct qe_snum snums[QE_NUM_OF_SNUM];   /* Dynamically allocated SNUMs */
+static u8 snums[QE_NUM_OF_SNUM];       /* Dynamically allocated SNUMs */
+static DECLARE_BITMAP(snum_state, QE_NUM_OF_SNUM);
 static unsigned int qe_num_of_snum;
 
 static phys_addr_t qebase = -1;
 
+static struct device_node *qe_get_device_node(void)
+{
+       struct device_node *qe;
+
+       /*
+        * Newer device trees have an "fsl,qe" compatible property for the QE
+        * node, but we still need to support older device trees.
+        */
+       qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
+       if (qe)
+               return qe;
+       return of_find_node_by_type(NULL, "qe");
+}
+
 static phys_addr_t get_qe_base(void)
 {
        struct device_node *qe;
@@ -71,12 +75,9 @@ static phys_addr_t get_qe_base(void)
        if (qebase != -1)
                return qebase;
 
-       qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
-       if (!qe) {
-               qe = of_find_node_by_type(NULL, "qe");
-               if (!qe)
-                       return qebase;
-       }
+       qe = qe_get_device_node();
+       if (!qe)
+               return qebase;
 
        ret = of_address_to_resource(qe, 0, &res);
        if (!ret)
@@ -170,12 +171,9 @@ unsigned int qe_get_brg_clk(void)
        if (brg_clk)
                return brg_clk;
 
-       qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
-       if (!qe) {
-               qe = of_find_node_by_type(NULL, "qe");
-               if (!qe)
-                       return brg_clk;
-       }
+       qe = qe_get_device_node();
+       if (!qe)
+               return brg_clk;
 
        prop = of_get_property(qe, "brg-frequency", &size);
        if (prop && size == sizeof(*prop))
@@ -281,7 +279,6 @@ EXPORT_SYMBOL(qe_clock_source);
  */
 static void qe_snums_init(void)
 {
-       int i;
        static const u8 snum_init_76[] = {
                0x04, 0x05, 0x0C, 0x0D, 0x14, 0x15, 0x1C, 0x1D,
                0x24, 0x25, 0x2C, 0x2D, 0x34, 0x35, 0x88, 0x89,
@@ -302,19 +299,39 @@ static void qe_snums_init(void)
                0x28, 0x29, 0x38, 0x39, 0x48, 0x49, 0x58, 0x59,
                0x68, 0x69, 0x78, 0x79, 0x80, 0x81,
        };
-       static const u8 *snum_init;
+       struct device_node *qe;
+       const u8 *snum_init;
+       int i;
 
-       qe_num_of_snum = qe_get_num_of_snums();
+       bitmap_zero(snum_state, QE_NUM_OF_SNUM);
+       qe_num_of_snum = 28; /* The default number of snum for threads is 28 */
+       qe = qe_get_device_node();
+       if (qe) {
+               i = of_property_read_variable_u8_array(qe, "fsl,qe-snums",
+                                                      snums, 1, QE_NUM_OF_SNUM);
+               if (i > 0) {
+                       of_node_put(qe);
+                       qe_num_of_snum = i;
+                       return;
+               }
+               /*
+                * Fall back to legacy binding of using the value of
+                * fsl,qe-num-snums to choose one of the static arrays
+                * above.
+                */
+               of_property_read_u32(qe, "fsl,qe-num-snums", &qe_num_of_snum);
+               of_node_put(qe);
+       }
 
-       if (qe_num_of_snum == 76)
+       if (qe_num_of_snum == 76) {
                snum_init = snum_init_76;
-       else
+       } else if (qe_num_of_snum == 28 || qe_num_of_snum == 46) {
                snum_init = snum_init_46;
-
-       for (i = 0; i < qe_num_of_snum; i++) {
-               snums[i].num = snum_init[i];
-               snums[i].state = QE_SNUM_STATE_FREE;
+       } else {
+               pr_err("QE: unsupported value of fsl,qe-num-snums: %u\n", qe_num_of_snum);
+               return;
        }
+       memcpy(snums, snum_init, qe_num_of_snum);
 }
 
 int qe_get_snum(void)
@@ -324,12 +341,10 @@ int qe_get_snum(void)
        int i;
 
        spin_lock_irqsave(&qe_lock, flags);
-       for (i = 0; i < qe_num_of_snum; i++) {
-               if (snums[i].state == QE_SNUM_STATE_FREE) {
-                       snums[i].state = QE_SNUM_STATE_USED;
-                       snum = snums[i].num;
-                       break;
-               }
+       i = find_first_zero_bit(snum_state, qe_num_of_snum);
+       if (i < qe_num_of_snum) {
+               set_bit(i, snum_state);
+               snum = snums[i];
        }
        spin_unlock_irqrestore(&qe_lock, flags);
 
@@ -339,14 +354,10 @@ EXPORT_SYMBOL(qe_get_snum);
 
 void qe_put_snum(u8 snum)
 {
-       int i;
+       const u8 *p = memchr(snums, snum, qe_num_of_snum);
 
-       for (i = 0; i < qe_num_of_snum; i++) {
-               if (snums[i].num == snum) {
-                       snums[i].state = QE_SNUM_STATE_FREE;
-                       break;
-               }
-       }
+       if (p)
+               clear_bit(p - snums, snum_state);
 }
 EXPORT_SYMBOL(qe_put_snum);
 
@@ -572,16 +583,9 @@ struct qe_firmware_info *qe_get_firmware_info(void)
 
        initialized = 1;
 
-       /*
-        * Newer device trees have an "fsl,qe" compatible property for the QE
-        * node, but we still need to support older device trees.
-       */
-       qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
-       if (!qe) {
-               qe = of_find_node_by_type(NULL, "qe");
-               if (!qe)
-                       return NULL;
-       }
+       qe = qe_get_device_node();
+       if (!qe)
+               return NULL;
 
        /* Find the 'firmware' child node */
        fw = of_get_child_by_name(qe, "firmware");
@@ -627,16 +631,9 @@ unsigned int qe_get_num_of_risc(void)
        unsigned int num_of_risc = 0;
        const u32 *prop;
 
-       qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
-       if (!qe) {
-               /* Older devices trees did not have an "fsl,qe"
-                * compatible property, so we need to look for
-                * the QE node by name.
-                */
-               qe = of_find_node_by_type(NULL, "qe");
-               if (!qe)
-                       return num_of_risc;
-       }
+       qe = qe_get_device_node();
+       if (!qe)
+               return num_of_risc;
 
        prop = of_get_property(qe, "fsl,qe-num-riscs", &size);
        if (prop && size == sizeof(*prop))
@@ -650,37 +647,7 @@ EXPORT_SYMBOL(qe_get_num_of_risc);
 
 unsigned int qe_get_num_of_snums(void)
 {
-       struct device_node *qe;
-       int size;
-       unsigned int num_of_snums;
-       const u32 *prop;
-
-       num_of_snums = 28; /* The default number of snum for threads is 28 */
-       qe = of_find_compatible_node(NULL, NULL, "fsl,qe");
-       if (!qe) {
-               /* Older devices trees did not have an "fsl,qe"
-                * compatible property, so we need to look for
-                * the QE node by name.
-                */
-               qe = of_find_node_by_type(NULL, "qe");
-               if (!qe)
-                       return num_of_snums;
-       }
-
-       prop = of_get_property(qe, "fsl,qe-num-snums", &size);
-       if (prop && size == sizeof(*prop)) {
-               num_of_snums = *prop;
-               if ((num_of_snums < 28) || (num_of_snums > QE_NUM_OF_SNUM)) {
-                       /* No QE ever has fewer than 28 SNUMs */
-                       pr_err("QE: number of snum is invalid\n");
-                       of_node_put(qe);
-                       return -EINVAL;
-               }
-       }
-
-       of_node_put(qe);
-
-       return num_of_snums;
+       return qe_num_of_snum;
 }
 EXPORT_SYMBOL(qe_get_num_of_snums);