Esempio n. 1
0
int modem_request_mmio(struct modemctl *mc)
{
    unsigned long flags;
    int ret;
    spin_lock_irqsave(&mc->lock, flags);
    mc->mmio_req_count++;
    ret = mc->mmio_owner;
    if (!ret) {
        if (mmio_sem(mc) == 1) {
            /* surprise! we already have control */
            ret = mc->mmio_owner = 1;
            wake_up(&mc->wq);
            modem_update_state(mc);
            MODEM_COUNT(mc,request_no_wait);
        } else {
            /* ask the modem for mmio access */
            if (modem_running(mc))
                modem_request_sem(mc);
            MODEM_COUNT(mc,request_wait);
        }
    } else {
        MODEM_COUNT(mc,request_no_wait);
    }
    /* TODO: timer to retry? */
    spin_unlock_irqrestore(&mc->lock, flags);
    return ret;
}
Esempio n. 2
0
static ssize_t modemctl_write(struct file *filp, const char __user *buf,
                              size_t count, loff_t *ppos)
{
    struct modemctl *mc = filp->private_data;
    u32 owner;
    char *data;
    loff_t pos = *ppos;
    unsigned long ret;

    mutex_lock(&mc->ctl_lock);
    data = (char __force *)mc->mmio + pos;
    owner = mmio_sem(mc);

    if (mc->status != MODEM_POWER_ON) {
        pr_err("modemctl_write: modem not powered on\n");
        ret = -EINVAL;
        goto done;
    }

    if (!owner) {
        pr_err("modemctl_write: doesn't own semaphore\n");
        ret = -EIO;
        goto done;
    }

    if (pos < 0) {
        ret = -EINVAL;
        goto done;
    }

    if (pos >= mc->mmsize) {
        ret = -EINVAL;
        goto done;
    }

    if (count > mc->mmsize - pos)
        count = mc->mmsize - pos;

    ret = copy_from_user(data, buf, count);
    if (ret) {
        ret = -EFAULT;
        goto done;
    }
    *ppos = pos + count;
    ret = count;

done:
    mutex_unlock(&mc->ctl_lock);
    return ret;
}
Esempio n. 3
0
static int modem_start(struct modemctl *mc, int ramdump)
{
	pr_info("[MODEM] modem_start() %s\n",
		ramdump ? "ramdump" : "normal");

	if (mc->status != MODEM_POWER_ON) {
		pr_err("[MODEM] modem not powered on\n");
		return -EINVAL;
	}

	if (readl(mc->mmio + OFF_MBOX_BP) != MODEM_MSG_SBL_DONE) {
		pr_err("[MODEM] bootloader not ready\n");
		return -EIO;
	}

	if (mmio_sem(mc) != 1) {
		pr_err("[MODEM] we do not own the semaphore\n");
		return -EIO;
	}

	writel(0, mc->mmio + OFF_SEM);
	if (ramdump) {
		mc->status = MODEM_BOOTING_RAMDUMP;
		mc->ramdump_size = 0;
		mc->ramdump_pos = 0;
		writel(MODEM_CMD_RAMDUMP_START, mc->mmio + OFF_MBOX_AP);

		/* TODO: timeout and fail */
		wait_event(mc->wq, mc->status == MODEM_DUMPING);
	} else {
		mc->status = MODEM_BOOTING_NORMAL;
		writel(MODEM_CMD_BINARY_LOAD, mc->mmio + OFF_MBOX_AP);

		/* TODO: timeout and fail */
		wait_event(mc->wq, modem_running(mc));
	}


	pr_info("[MODEM] modem_start() DONE\n");
	return 0;
}
Esempio n. 4
0
static irqreturn_t modemctl_mbox_irq_handler(int irq, void *_mc)
{
    struct modemctl *mc = _mc;
    unsigned cmd;
    unsigned long flags;

    cmd = readl(mc->mmio + OFF_MBOX_BP);

    if (unlikely(mc->status != MODEM_RUNNING)) {
        modemctl_handle_offline(mc, cmd);
        return IRQ_HANDLED;
    }

    if (!(cmd & MB_VALID)) {
        if (cmd == MODEM_MSG_LOGDUMP_DONE) {
            pr_info("modem: logdump done!\n");
            mc->logdump_data = 1;
            wake_up(&mc->wq);
        } else {
            pr_info("modem: what is %08x\n",cmd);
        }
        return IRQ_HANDLED;
    }

    spin_lock_irqsave(&mc->lock, flags);

    if (cmd & MB_COMMAND) {
        switch (cmd & 15) {
        case MBC_REQ_SEM:
            if (mmio_sem(mc) == 0) {
                /* Sometimes the modem may ask for the
                 * sem when it already owns it.  Humor
                 * it and ack that request.
                 */
                writel(MB_COMMAND | MB_VALID | MBC_RES_SEM,
                       mc->mmio + OFF_MBOX_AP);
                MODEM_COUNT(mc,bp_req_confused);
            } else if (mc->mmio_req_count == 0) {
                /* No references? Give it to the modem. */
                modem_update_state(mc);
                mc->mmio_owner = 0;
                writel(0, mc->mmio + OFF_SEM);
                writel(MB_COMMAND | MB_VALID | MBC_RES_SEM,
                       mc->mmio + OFF_MBOX_AP);
                MODEM_COUNT(mc,bp_req_instant);
                goto done;
            } else {
                /* Busy now, remember the modem needs it. */
                mc->mmio_bp_request = 1;
                MODEM_COUNT(mc,bp_req_delayed);
                break;
            }
        case MBC_RES_SEM:
            break;
        case MBC_PHONE_START:
            /* TODO: should we avoid sending any other messages
             * to the modem until this message is received and
             * acknowledged?
             */
            writel(MB_COMMAND | MB_VALID |
                   MBC_INIT_END | CP_BOOT_AIRPLANE | AP_OS_ANDROID,
                   mc->mmio + OFF_MBOX_AP);

            /* TODO: probably unsafe to send this back-to-back
             * with the INIT_END message.
             */
            /* if somebody is waiting for mmio access... */
            if (mc->mmio_req_count)
                modem_request_sem(mc);
            break;
        case MBC_RESET:
            pr_err("$$$ MODEM RESET $$$\n");
            mc->status = MODEM_CRASHED;
            wake_up(&mc->wq);
            break;
        case MBC_ERR_DISPLAY: {
            char buf[SIZ_ERROR_MSG + 1];
            int i;
            pr_err("$$$ MODEM ERROR $$$\n");
            mc->status = MODEM_CRASHED;
            wake_up(&mc->wq);
            memcpy(buf, mc->mmio + OFF_ERROR_MSG, SIZ_ERROR_MSG);
            for (i = 0; i < SIZ_ERROR_MSG; i++)
                if ((buf[i] < 0x20) || (buf[1] > 0x7e))
                    buf[i] = 0x20;
            buf[i] = 0;
            i--;
            while ((i > 0) && (buf[i] == 0x20))
                buf[i--] = 0;
            pr_err("$$$ %s $$$\n", buf);
            break;
        }
        case MBC_SUSPEND:
            break;
        case MBC_RESUME:
            break;
        }
    }

    /* On *any* interrupt from the modem it may have given
     * us ownership of the mmio hw semaphore.  If that
     * happens, we should claim the semaphore if we have
     * threads waiting for it and we should process any
     * messages that the modem has enqueued in its fifos
     * by calling modem_handle_io().
     */
    if (mmio_sem(mc) == 1) {
        if (!mc->mmio_owner) {
            modem_update_state(mc);
            if (mc->mmio_req_count) {
                mc->mmio_owner = 1;
                wake_up(&mc->wq);
            }
        }

        modem_handle_io(mc);

        /* If we have a signal to send and we're not
         * hanging on to the mmio hw semaphore, give
         * it back to the modem and send the signal.
         * Otherwise this will happen when we give up
         * the mmio hw sem in modem_release_mmio().
         */
        if (mc->mmio_signal_bits && !mc->mmio_owner) {
            writel(0, mc->mmio + OFF_SEM);
            writel(MB_VALID | mc->mmio_signal_bits,
                   mc->mmio + OFF_MBOX_AP);
            mc->mmio_signal_bits = 0;
        }
    }
done:
    spin_unlock_irqrestore(&mc->lock, flags);
    return IRQ_HANDLED;
}