/*
 * ---------------------------------------------------------------------------
 *  unifi_send_resources_available
 *
 *      Examines whether there is available space to queue
 *      a signal in the command or traffic queue
 *
 *  Arguments:
 *      card        Pointer to card context struct
 *      sigptr      Pointer to signal.
 *
 *  Returns:
 *      CSR_RESULT_SUCCESS if resources available
 *      CSR_WIFI_HIP_RESULT_NO_SPACE if there was no free signal queue entry
 *
 *  Notes:
 * ---------------------------------------------------------------------------
 */
CsrResult unifi_send_resources_available(card_t *card, const CsrUint8 *sigptr)
{
    q_t *sig_soft_q;
    CsrUint16 signal_id = GET_SIGNAL_ID(sigptr);

    /*
     * If the signal is a CSR_MA_PACKET_REQUEST ,
     * we send it using the traffic soft queue. Else we use the command soft queue.
     */
    if (signal_id == CSR_MA_PACKET_REQUEST_ID)
    {
        CsrUint16 frame_priority;
        CsrUint32 priority_q;

        /* Map the frame priority to a traffic queue index. */
        frame_priority = GET_PACKED_MA_PACKET_REQUEST_FRAME_PRIORITY(sigptr);
        priority_q = unifi_frame_priority_to_queue((CSR_PRIORITY)frame_priority);

        sig_soft_q = &card->fh_traffic_queue[priority_q];
    }
    else
    {
        sig_soft_q = &card->fh_command_queue;
    }

    /* Check that the fh_data_queue has a free slot */
    if (!CSR_WIFI_HIP_Q_SLOTS_FREE(sig_soft_q))
    {
        unifi_notice(card->ospriv, "unifi_send_resources_available: %s full\n",
                     sig_soft_q->name);
        return CSR_WIFI_HIP_RESULT_NO_SPACE;
    }

    return CSR_RESULT_SUCCESS;
} /* unifi_send_resources_available() */
示例#2
0
void
uf_sme_complete_request(unifi_priv_t *priv, CsrResult reply_status, const char *func)
{
    if (priv == NULL) {
        unifi_error(priv, "sme_complete_request: Invalid priv\n");
        return;
    }

    if (priv->sme_reply.request_status != SME_REQUEST_PENDING) {
        unifi_notice(priv,
                    "sme_complete_request: request not pending %s (s:%d)\n",
                    (func ? func : ""), priv->sme_reply.request_status);
        return;
    }
    unifi_trace(priv, UDBG5,
                "sme_complete_request: completed %s (s:%d)\n",
                (func ? func : ""), priv->sme_reply.request_status);

    priv->sme_reply.request_status = SME_REQUEST_RECEIVED;
    priv->sme_reply.reply_status = reply_status;

    wake_up_interruptible(&priv->sme_request_wq);

    return;
}
示例#3
0
/*
 * ---------------------------------------------------------------------------
 *  uf_register_netdev
 *
 *      Registers the network interface, installes the qdisc,
 *      and registers the inet handler.
 *      In the porting exercise, register the driver to the network
 *      stack if necessary.
 *
 *  Arguments:
 *      priv          Pointer to driver context.
 *
 *  Returns:
 *      O on success, non-zero otherwise.
 *
 *  Notes:
 *      We will only unregister when the card is ejected, so we must
 *      only do it once.
 * ---------------------------------------------------------------------------
 */
int
uf_register_netdev(unifi_priv_t *priv, int interfaceTag)
{
    int r;
    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];

    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
        unifi_error(priv, "uf_register_netdev bad interfaceTag\n");
        return -EINVAL;
    }

    /*
     * Allocates a device number and registers device with the network
     * stack.
     */
    unifi_trace(priv, UDBG5, "uf_register_netdev: netdev %d - 0x%p\n",
            interfaceTag, priv->netdev[interfaceTag]);
    r = register_netdev(priv->netdev[interfaceTag]);
    if (r) {
        unifi_error(priv, "Failed to register net device\n");
        return -EINVAL;
    }

    /* The device is registed */
    interfacePriv->netdev_registered = 1;

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
#ifdef CONFIG_NET_SCHED
    /*
     * IMPORTANT:
     * uf_install_qdisc() holds the network device lock, we can not
     * install the qdisk before the network device is registered.
     */
    r = uf_install_qdisc(priv->netdev[interfaceTag]);
    if (r) {
        unifi_error(priv, "Failed to install qdisc\n");
        return r;
    }
#endif /* CONFIG_NET_SCHED */
#endif /* LINUX_VERSION_CODE */

#ifdef CSR_SUPPORT_SME
    /*
     * Register the inet handler; it notifies us for changes in the IP address.
     */
    uf_register_inet_notifier();
#endif /* CSR_SUPPORT_SME */

    unifi_notice(priv, "unifi%d is %s\n",
            priv->instance, priv->netdev[interfaceTag]->name);

    return 0;
} /* uf_register_netdev */
示例#4
0
static int
_sme_wait_for_reply(unifi_priv_t *priv,
        unsigned long timeout, const char *func)
{
    long r;

    unifi_trace(priv, UDBG5, "sme_wait_for_reply: %s sleep\n", func ? func : "");
    r = wait_event_interruptible_timeout(priv->sme_request_wq,
                                         (priv->sme_reply.request_status != SME_REQUEST_PENDING),
                                         msecs_to_jiffies(timeout));
    unifi_trace(priv, UDBG5, "sme_wait_for_reply: %s awake (%d)\n", func ? func : "", r);

    if (r == -ERESTARTSYS) {
        /* The thread was killed */
        unifi_info(priv, "ERESTARTSYS in _sme_wait_for_reply\n");
        up(&priv->sme_sem);
        return r;
    }
    if (priv->sme_reply.request_status == SME_REQUEST_CANCELLED) {
        unifi_trace(priv, UDBG5, "Cancelled waiting for SME to reply (%s s:%d, t:%d, r:%d)\n",
                    (func ? func : ""), priv->sme_reply.request_status, timeout, r);

        /* Release the SME semaphore that was downed in sme_init_request() */
        up(&priv->sme_sem);
        return -EIO; /* fail the ioctl */
    }
    if ((r == 0) && (priv->sme_reply.request_status != SME_REQUEST_RECEIVED)) {
        unifi_notice(priv, "Timeout waiting for SME to reply (%s s:%d, t:%d)\n",
                     (func ? func : ""), priv->sme_reply.request_status, timeout);

        priv->sme_reply.request_status = SME_REQUEST_TIMEDOUT;

        /* Release the SME semaphore that was downed in sme_init_request() */
        up(&priv->sme_sem);

        return -ETIMEDOUT;
    }

    unifi_trace(priv, UDBG5, "sme_wait_for_reply: %s received (%d)\n",
                func ? func : "", r);

    /* Release the SME semaphore that was downed in sme_init_request() */
    up(&priv->sme_sem);

    return 0;
} /* sme_wait_for_reply() */
示例#5
0
/*
 * ---------------------------------------------------------------------------
 *  uf_register_netdev
 *
 *      Registers the network interface, installes the qdisc,
 *      and registers the inet handler.
 *      In the porting exercise, register the driver to the network
 *      stack if necessary.
 *
 *  Arguments:
 *      priv          Pointer to driver context.
 *
 *  Returns:
 *      O on success, non-zero otherwise.
 *
 *  Notes:
 *      We will only unregister when the card is ejected, so we must
 *      only do it once.
 * ---------------------------------------------------------------------------
 */
int
uf_register_netdev(unifi_priv_t *priv, int interfaceTag)
{
    int r;
    netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];

    if (interfaceTag >= CSR_WIFI_NUM_INTERFACES) {
        unifi_error(priv, "uf_register_netdev bad interfaceTag\n");
        return -EINVAL;
    }

    /*
     * Allocates a device number and registers device with the network
     * stack.
     */
    unifi_trace(priv, UDBG5, "uf_register_netdev: netdev %d - 0x%p\n",
            interfaceTag, priv->netdev[interfaceTag]);
    r = register_netdev(priv->netdev[interfaceTag]);
    if (r) {
        unifi_error(priv, "Failed to register net device\n");
        return -EINVAL;
    }

    /* The device is registed */
    interfacePriv->netdev_registered = 1;

#ifdef CSR_SUPPORT_SME
    /*
     * Register the inet handler; it notifies us for changes in the IP address.
     */
    uf_register_inet_notifier();
#endif /* CSR_SUPPORT_SME */

    unifi_notice(priv, "unifi%d is %s\n",
            priv->instance, priv->netdev[interfaceTag]->name);

    return 0;
} /* uf_register_netdev */
示例#6
0
/*
 * ---------------------------------------------------------------------------
 *  unregister_unifi_sdio
 *
 *      Call from SDIO driver when it detects that UniFi has been removed.
 *
 *  Arguments:
 *      bus_id          Number of the card that was ejected.
 *
 *  Returns:
 *      None.
 * ---------------------------------------------------------------------------
 */
static void
unregister_unifi_sdio(int bus_id)
{
    unifi_priv_t *priv;
    int interfaceTag=0;
    u8 reason = CONFIG_IND_EXIT;

    if ((bus_id < 0) || (bus_id >= MAX_UNIFI_DEVS)) {
        unifi_error(NULL, "unregister_unifi_sdio: invalid device %d\n",
                bus_id);
        return;
    }

    priv = Unifi_instances[bus_id];
    if (priv == NULL) {
        unifi_error(priv, "unregister_unifi_sdio: device %d is not registered\n",
                bus_id);
        return;
    }

    /* Stop the network traffic before freeing the core. */
    for(interfaceTag=0;interfaceTag<priv->totalInterfaceCount;interfaceTag++)
    {
        netInterface_priv_t *interfacePriv = priv->interfacePriv[interfaceTag];
        if(interfacePriv->netdev_registered)
        {
            netif_carrier_off(priv->netdev[interfaceTag]);
            netif_tx_stop_all_queues(priv->netdev[interfaceTag]);
        }
    }

#ifdef CSR_NATIVE_LINUX
    /*
     * If the unifi thread was started, signal it to stop.  This
     * should cause any userspace processes with open unifi device to
     * close them.
     */
    uf_stop_thread(priv, &priv->bh_thread);

    /* Unregister the interrupt handler */
    if (csr_sdio_linux_remove_irq(priv->sdio)) {
        unifi_notice(priv,
                "csr_sdio_linux_remove_irq failed to talk to card.\n");
    }

    /* Ensure no MLME functions are waiting on a the mlme_event semaphore. */
    uf_abort_mlme(priv);
#endif /* CSR_NATIVE_LINUX */

    ul_log_config_ind(priv, &reason, sizeof(u8));

    /* Deregister the UDI hook from the core. */
    unifi_remove_udi_hook(priv->card, logging_handler);

    uf_put_instance(bus_id);

    /*
     * Wait until the device is cleaned up. i.e., when all userspace
     * processes have closed any open unifi devices.
     */
    wait_event(Unifi_cleanup_wq, In_use[bus_id] == UNIFI_DEV_CLEANUP);
    unifi_trace(NULL, UDBG5, "Received clean up event\n");

    /* Now we can free the private context and the char device nodes */
    cleanup_unifi_sdio(priv);

} /* unregister_unifi_sdio() */
示例#7
0
/*
 * ---------------------------------------------------------------------------
 *  register_unifi_sdio
 *
 *      This function is called from the Probe (or equivalent) method of
 *      the SDIO driver when a UniFi card is detected.
 *      We allocate the Linux net_device struct, initialise the HIP core
 *      lib, create the char device nodes and start the userspace helper
 *      to initialise the device.
 *
 *  Arguments:
 *      sdio_dev        Pointer to SDIO context handle to use for all
 *                      SDIO ops.
 *      bus_id          A small number indicating the SDIO card position on the
 *                      bus. Typically this is the slot number, e.g. 0, 1 etc.
 *                      Valid values are 0 to MAX_UNIFI_DEVS-1.
 *      dev             Pointer to kernel device manager struct.
 *
 *  Returns:
 *      Pointer to the unifi instance, or NULL on error.
 * ---------------------------------------------------------------------------
 */
static unifi_priv_t *
register_unifi_sdio(CsrSdioFunction *sdio_dev, int bus_id, struct device *dev)
{
    unifi_priv_t *priv = NULL;
    int r = -1;
    CsrResult csrResult;

    if ((bus_id < 0) || (bus_id >= MAX_UNIFI_DEVS)) {
        unifi_error(priv, "register_unifi_sdio: invalid device %d\n",
                bus_id);
        return NULL;
    }

    down(&Unifi_instance_mutex);

    if (In_use[bus_id] != UNIFI_DEV_NOT_IN_USE) {
        unifi_error(priv, "register_unifi_sdio: device %d is already in use\n",
                bus_id);
        goto failed0;
    }


    /* Allocate device private and net_device structs */
    priv = uf_alloc_netdevice(sdio_dev, bus_id);
    if (priv == NULL) {
        unifi_error(priv, "Failed to allocate driver private\n");
        goto failed0;
    }

    priv->unifi_device = dev;

    SET_NETDEV_DEV(priv->netdev[0], dev);

    /* We are not ready to send data yet. */
    netif_carrier_off(priv->netdev[0]);

    /* Allocate driver context. */
    priv->card = unifi_alloc_card(priv->sdio, priv);
    if (priv->card == NULL) {
        unifi_error(priv, "Failed to allocate UniFi driver card struct.\n");
        goto failed1;
    }

    if (Unifi_instances[bus_id]) {
        unifi_error(priv, "Internal error: instance for slot %d is already taken\n",
                bus_id);
    }
    Unifi_instances[bus_id] = priv;
    In_use[bus_id] = UNIFI_DEV_IN_USE;

    /* Save the netdev_priv for use by the netdev event callback mechanism */
    Unifi_netdev_instances[bus_id * CSR_WIFI_NUM_INTERFACES] = netdev_priv(priv->netdev[0]);

    /* Initialise the mini-coredump capture buffers */
    csrResult = unifi_coredump_init(priv->card, (u16)coredump_max);
    if (csrResult != CSR_RESULT_SUCCESS) {
        unifi_error(priv, "Couldn't allocate mini-coredump buffers\n");
    }

    /* Create the character device nodes */
    r = uf_create_device_nodes(priv, bus_id);
    if (r) {
        goto failed1;
    }

    /*
     * We use the slot number as unifi device index.
     */
    scnprintf(priv->proc_entry_name, 64, "driver/unifi%d", priv->instance);
    /*
     * The following complex casting is in place in order to eliminate 64-bit compilation warning
     * "cast to/from pointer from/to integer of different size"
     */
    if (!proc_create_data(priv->proc_entry_name, 0, NULL,
			  &uf_proc_fops, (void *)(long)priv->instance))
    {
        unifi_error(priv, "unifi: can't create /proc/driver/unifi\n");
    }

    /* Allocate the net_device for interfaces other than 0. */
    {
        int i;
        priv->totalInterfaceCount =0;

        for(i=1;i<CSR_WIFI_NUM_INTERFACES;i++)
        {
            if( !uf_alloc_netdevice_for_other_interfaces(priv,i) )
            {
                /* error occured while allocating the net_device for interface[i]. The net_device are
                 * allocated for the interfaces with id<i. Dont worry, all the allocated net_device will
                 * be releasing chen the control goes to the label failed0.
                 */
                unifi_error(priv, "Failed to allocate driver private for interface[%d]\n",i);
                goto failed0;
            }
            else
            {
                SET_NETDEV_DEV(priv->netdev[i], dev);

                /* We are not ready to send data yet. */
                netif_carrier_off(priv->netdev[i]);

                /* Save the netdev_priv for use by the netdev event callback mechanism */
                Unifi_netdev_instances[bus_id * CSR_WIFI_NUM_INTERFACES + i] = netdev_priv(priv->netdev[i]);
            }
        }

        for(i=0;i<CSR_WIFI_NUM_INTERFACES;i++)
        {
            netInterface_priv_t *interfacePriv = priv->interfacePriv[i];
            interfacePriv->netdev_registered=0;
        }
    }

#ifdef CSR_WIFI_RX_PATH_SPLIT
    if (signal_buffer_init(priv, CSR_WIFI_RX_SIGNAL_BUFFER_SIZE))
    {
        unifi_error(priv,"Failed to allocate shared memory for T-H signals\n");
        goto failed2;
    }
    priv->rx_workqueue = create_singlethread_workqueue("rx_workq");
    if (priv->rx_workqueue == NULL) {
        unifi_error(priv,"create_singlethread_workqueue failed \n");
        goto failed3;
    }
    INIT_WORK(&priv->rx_work_struct, rx_wq_handler);
#endif

#ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
    if (log_hip_signals)
    {
        uf_register_hip_offline_debug(priv);
    }
#endif

    /* Initialise the SME related threads and parameters */
    r = uf_sme_init(priv);
    if (r) {
        unifi_error(priv, "SME initialisation failed.\n");
        goto failed4;
    }

    /*
     * Run the userspace helper program (unififw) to perform
     * the device initialisation.
     */
    unifi_trace(priv, UDBG1, "run UniFi helper app...\n");
    r = uf_run_unifihelper(priv);
    if (r) {
        unifi_notice(priv, "unable to run UniFi helper app\n");
        /* Not a fatal error. */
    }

    up(&Unifi_instance_mutex);

    return priv;

failed4:
#ifdef CSR_WIFI_HIP_DEBUG_OFFLINE
if (log_hip_signals)
{
    uf_unregister_hip_offline_debug(priv);
}
#endif
#ifdef CSR_WIFI_RX_PATH_SPLIT
    flush_workqueue(priv->rx_workqueue);
    destroy_workqueue(priv->rx_workqueue);
failed3:
    signal_buffer_free(priv,CSR_WIFI_RX_SIGNAL_BUFFER_SIZE);
failed2:
#endif
    /* Remove the device nodes */
    uf_destroy_device_nodes(priv);
failed1:
    /* Deregister priv->netdev_client */
    ul_deregister_client(priv->netdev_client);

failed0:
    if (priv && priv->card) {
        unifi_coredump_free(priv->card);
        unifi_free_card(priv->card);
    }
    if (priv) {
        uf_free_netdevice(priv);
    }

    up(&Unifi_instance_mutex);

    return NULL;
} /* register_unifi_sdio() */