/* * --------------------------------------------------------------------------- * 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() */
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; }
/* * --------------------------------------------------------------------------- * 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 */
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() */
/* * --------------------------------------------------------------------------- * 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 */
/* * --------------------------------------------------------------------------- * 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() */
/* * --------------------------------------------------------------------------- * 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() */