int bitmap_scnprintf(char *buf, unsigned int buflen,
        const unsigned long *maskp, int nmaskbits)
 {
-       int i, word, bit, len = 0;
-       unsigned long val;
-       const char *sep = "";
-       int chunksz;
-       u32 chunkmask;
-
-       chunksz = nmaskbits & (CHUNKSZ - 1);
-       if (chunksz == 0)
-               chunksz = CHUNKSZ;
-
-       i = ALIGN(nmaskbits, CHUNKSZ) - CHUNKSZ;
-       for (; i >= 0; i -= CHUNKSZ) {
-               chunkmask = ((1ULL << chunksz) - 1);
-               word = i / BITS_PER_LONG;
-               bit = i % BITS_PER_LONG;
-               val = (maskp[word] >> bit) & chunkmask;
-               len += scnprintf(buf+len, buflen-len, "%s%0*lx", sep,
-                       (chunksz+3)/4, val);
-               chunksz = CHUNKSZ;
-               sep = ",";
-       }
-       return len;
+       return scnprintf(buf, buflen, "%*pb", nmaskbits, maskp);
 }
 EXPORT_SYMBOL(bitmap_scnprintf);
 
 }
 EXPORT_SYMBOL(bitmap_parse_user);
 
-/*
- * bscnl_emit(buf, buflen, rbot, rtop, bp)
- *
- * Helper routine for bitmap_scnlistprintf().  Write decimal number
- * or range to buf, suppressing output past buf+buflen, with optional
- * comma-prefix.  Return len of what was written to *buf, excluding the
- * trailing \0.
- */
-static inline int bscnl_emit(char *buf, int buflen, int rbot, int rtop, int len)
-{
-       if (len > 0)
-               len += scnprintf(buf + len, buflen - len, ",");
-       if (rbot == rtop)
-               len += scnprintf(buf + len, buflen - len, "%d", rbot);
-       else
-               len += scnprintf(buf + len, buflen - len, "%d-%d", rbot, rtop);
-       return len;
-}
-
 /**
  * bitmap_scnlistprintf - convert bitmap to list format ASCII string
  * @buf: byte buffer into which string is placed
 int bitmap_scnlistprintf(char *buf, unsigned int buflen,
        const unsigned long *maskp, int nmaskbits)
 {
-       int len = 0;
-       /* current bit is 'cur', most recently seen range is [rbot, rtop] */
-       int cur, rbot, rtop;
-
-       if (buflen == 0)
-               return 0;
-       buf[0] = 0;
-
-       rbot = cur = find_first_bit(maskp, nmaskbits);
-       while (cur < nmaskbits) {
-               rtop = cur;
-               cur = find_next_bit(maskp, nmaskbits, cur+1);
-               if (cur >= nmaskbits || cur > rtop + 1) {
-                       len = bscnl_emit(buf, buflen, rbot, rtop, len);
-                       rbot = cur;
-               }
-       }
-       return len;
+       return scnprintf(buf, buflen, "%*pbl", nmaskbits, maskp);
 }
 EXPORT_SYMBOL(bitmap_scnlistprintf);
 
 
        return buf;
 }
 
+static noinline_for_stack
+char *bitmap_string(char *buf, char *end, unsigned long *bitmap,
+                   struct printf_spec spec, const char *fmt)
+{
+       const int CHUNKSZ = 32;
+       int nr_bits = max_t(int, spec.field_width, 0);
+       int i, chunksz;
+       bool first = true;
+
+       /* reused to print numbers */
+       spec = (struct printf_spec){ .flags = SMALL | ZEROPAD, .base = 16 };
+
+       chunksz = nr_bits & (CHUNKSZ - 1);
+       if (chunksz == 0)
+               chunksz = CHUNKSZ;
+
+       i = ALIGN(nr_bits, CHUNKSZ) - CHUNKSZ;
+       for (; i >= 0; i -= CHUNKSZ) {
+               u32 chunkmask, val;
+               int word, bit;
+
+               chunkmask = ((1ULL << chunksz) - 1);
+               word = i / BITS_PER_LONG;
+               bit = i % BITS_PER_LONG;
+               val = (bitmap[word] >> bit) & chunkmask;
+
+               if (!first) {
+                       if (buf < end)
+                               *buf = ',';
+                       buf++;
+               }
+               first = false;
+
+               spec.field_width = DIV_ROUND_UP(chunksz, 4);
+               buf = number(buf, end, val, spec);
+
+               chunksz = CHUNKSZ;
+       }
+       return buf;
+}
+
+static noinline_for_stack
+char *bitmap_list_string(char *buf, char *end, unsigned long *bitmap,
+                        struct printf_spec spec, const char *fmt)
+{
+       int nr_bits = max_t(int, spec.field_width, 0);
+       /* current bit is 'cur', most recently seen range is [rbot, rtop] */
+       int cur, rbot, rtop;
+       bool first = true;
+
+       /* reused to print numbers */
+       spec = (struct printf_spec){ .base = 10 };
+
+       rbot = cur = find_first_bit(bitmap, nr_bits);
+       while (cur < nr_bits) {
+               rtop = cur;
+               cur = find_next_bit(bitmap, nr_bits, cur + 1);
+               if (cur < nr_bits && cur <= rtop + 1)
+                       continue;
+
+               if (!first) {
+                       if (buf < end)
+                               *buf = ',';
+                       buf++;
+               }
+               first = false;
+
+               buf = number(buf, end, rbot, spec);
+               if (rbot < rtop) {
+                       if (buf < end)
+                               *buf = '-';
+                       buf++;
+
+                       buf = number(buf, end, rtop, spec);
+               }
+
+               rbot = cur;
+       }
+       return buf;
+}
+
 static noinline_for_stack
 char *mac_address_string(char *buf, char *end, u8 *addr,
                         struct printf_spec spec, const char *fmt)
  * - 'B' For backtraced symbolic direct pointers with offset
  * - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref]
  * - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201]
+ * - 'b[l]' For a bitmap, the number of bits is determined by the field
+ *       width which must be explicitly specified either as part of the
+ *       format string '%32b[l]' or through '%*b[l]', [l] selects
+ *       range-list format instead of hex format
  * - 'M' For a 6-byte MAC address, it prints the address in the
  *       usual colon-separated hex notation
  * - 'm' For a 6-byte MAC address, it prints the hex address without colons
                return resource_string(buf, end, ptr, spec, fmt);
        case 'h':
                return hex_string(buf, end, ptr, spec, fmt);
+       case 'b':
+               switch (fmt[1]) {
+               case 'l':
+                       return bitmap_list_string(buf, end, ptr, spec, fmt);
+               default:
+                       return bitmap_string(buf, end, ptr, spec, fmt);
+               }
        case 'M':                       /* Colon separated: 00:01:02:03:04:05 */
        case 'm':                       /* Contiguous: 000102030405 */
                                        /* [mM]F (FDDI) */
  * %pB output the name of a backtrace symbol with its offset
  * %pR output the address range in a struct resource with decoded flags
  * %pr output the address range in a struct resource with raw flags
+ * %pb output the bitmap with field width as the number of bits
+ * %pbl output the bitmap as range list with field width as the number of bits
  * %pM output a 6-byte MAC address with colons
  * %pMR output a 6-byte MAC address with colons in reversed order
  * %pMF output a 6-byte MAC address with dashes