示例#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;
}
示例#2
0
static int vnet_xmit(struct sk_buff *skb, struct net_device *ndev)
{
	struct vnet *vn = netdev_priv(ndev);
	struct modemctl *mc = vn->mc;
	unsigned long flags;

	spin_lock_irqsave(&mc->lock, flags);
	if (readl(mc->mmio + OFF_SEM) & 1) {
		/* if we happen to hold the hw mmio sem, transmit NOW */
		if (handle_raw_tx(mc, skb)) {
			wake_lock(&mc->ip_tx_wakelock);
			skb_queue_tail(&vn->txq, skb);
		} else {
			MODEM_COUNT(mc, tx_no_delay);
		}
		if (!mc->mmio_owner) {
			/* if we don't own the semaphore, immediately
			 * give it back to the modem and signal the modem
			 * to process the packet
			 */
			writel(0, mc->mmio + OFF_SEM);
			writel(MB_VALID | MBD_SEND_RAW,
			       mc->mmio + OFF_MBOX_AP);
			MODEM_COUNT(mc, tx_bp_signaled);
		}
	} else {
		/* otherwise request the hw mmio sem and queue */
		modem_request_sem(mc);
		skb_queue_tail(&vn->txq, skb);
		MODEM_COUNT(mc, tx_queued);
	}
	spin_unlock_irqrestore(&mc->lock, flags);

	return NETDEV_TX_OK;
}
示例#3
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;
}