#define J_TARGET(pc,target)    \
                (((unsigned long)(pc) & 0xf0000000) | ((target) << 2))
 
-static inline int is_ra_save_ins(union mips_instruction *ip)
+static inline int is_ra_save_ins(union mips_instruction *ip, int *poff)
 {
 #ifdef CONFIG_CPU_MICROMIPS
        /*
         * microMIPS is way more fun...
         */
        if (mm_insn_16bit(ip->halfword[1])) {
-               return (ip->mm16_r5_format.opcode == mm_swsp16_op &&
-                       ip->mm16_r5_format.rt == 31) ||
-                      (ip->mm16_m_format.opcode == mm_pool16c_op &&
-                       ip->mm16_m_format.func == mm_swm16_op);
+               switch (ip->mm16_r5_format.opcode) {
+               case mm_swsp16_op:
+                       if (ip->mm16_r5_format.rt != 31)
+                               return 0;
+
+                       *poff = ip->mm16_r5_format.simmediate;
+                       *poff = (*poff << 2) / sizeof(ulong);
+                       return 1;
+
+               case mm_pool16c_op:
+                       switch (ip->mm16_m_format.func) {
+                       case mm_swm16_op:
+                               *poff = ip->mm16_m_format.imm;
+                               *poff += 1 + ip->mm16_m_format.rlist;
+                               *poff = (*poff << 2) / sizeof(ulong);
+                               return 1;
+
+                       default:
+                               return 0;
+                       }
+
+               default:
+                       return 0;
+               }
        }
-       else {
-               return (ip->mm_m_format.opcode == mm_pool32b_op &&
-                       ip->mm_m_format.rd > 9 &&
-                       ip->mm_m_format.base == 29 &&
-                       ip->mm_m_format.func == mm_swm32_func) ||
-                      (ip->i_format.opcode == mm_sw32_op &&
-                       ip->i_format.rs == 29 &&
-                       ip->i_format.rt == 31);
+
+       switch (ip->i_format.opcode) {
+       case mm_sw32_op:
+               if (ip->i_format.rs != 29)
+                       return 0;
+               if (ip->i_format.rt != 31)
+                       return 0;
+
+               *poff = ip->i_format.simmediate / sizeof(ulong);
+               return 1;
+
+       case mm_pool32b_op:
+               switch (ip->mm_m_format.func) {
+               case mm_swm32_func:
+                       if (ip->mm_m_format.rd < 0x10)
+                               return 0;
+                       if (ip->mm_m_format.base != 29)
+                               return 0;
+
+                       *poff = ip->mm_m_format.simmediate;
+                       *poff += (ip->mm_m_format.rd & 0xf) * sizeof(u32);
+                       *poff /= sizeof(ulong);
+                       return 1;
+               default:
+                       return 0;
+               }
+
+       default:
+               return 0;
        }
 #else
        /* sw / sd $ra, offset($sp) */
-       return (ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) &&
-               ip->i_format.rs == 29 &&
-               ip->i_format.rt == 31;
+       if ((ip->i_format.opcode == sw_op || ip->i_format.opcode == sd_op) &&
+               ip->i_format.rs == 29 && ip->i_format.rt == 31) {
+               *poff = ip->i_format.simmediate / sizeof(ulong);
+               return 1;
+       }
+
+       return 0;
 #endif
 }
 
                        }
                        continue;
                }
-               if (info->pc_offset == -1 && is_ra_save_ins(&insn)) {
-                       info->pc_offset =
-                               ip->i_format.simmediate / sizeof(long);
+               if (info->pc_offset == -1 &&
+                   is_ra_save_ins(&insn, &info->pc_offset))
                        break;
-               }
        }
        if (info->frame_size && info->pc_offset >= 0) /* nested */
                return 0;