| #include "headers.h" |
| |
| struct net_device *gblpnetdev; |
| |
| static INT bcm_open(struct net_device *dev) |
| { |
| struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); |
| |
| if (Adapter->fw_download_done == FALSE) { |
| pr_notice(PFX "%s: link up failed (download in progress)\n", |
| dev->name); |
| return -EBUSY; |
| } |
| |
| if (netif_msg_ifup(Adapter)) |
| pr_info(PFX "%s: enabling interface\n", dev->name); |
| |
| if (Adapter->LinkUpStatus) { |
| if (netif_msg_link(Adapter)) |
| pr_info(PFX "%s: link up\n", dev->name); |
| |
| netif_carrier_on(Adapter->dev); |
| netif_start_queue(Adapter->dev); |
| } |
| |
| return 0; |
| } |
| |
| static INT bcm_close(struct net_device *dev) |
| { |
| struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); |
| |
| if (netif_msg_ifdown(Adapter)) |
| pr_info(PFX "%s: disabling interface\n", dev->name); |
| |
| netif_carrier_off(dev); |
| netif_stop_queue(dev); |
| |
| return 0; |
| } |
| |
| static u16 bcm_select_queue(struct net_device *dev, struct sk_buff *skb) |
| { |
| return ClassifyPacket(netdev_priv(dev), skb); |
| } |
| |
| /******************************************************************* |
| * Function - bcm_transmit() |
| * |
| * Description - This is the main transmit function for our virtual |
| * interface(eth0). It handles the ARP packets. It |
| * clones this packet and then Queue it to a suitable |
| * Queue. Then calls the transmit_packet(). |
| * |
| * Parameter - skb - Pointer to the socket buffer structure |
| * dev - Pointer to the virtual net device structure |
| * |
| *********************************************************************/ |
| |
| static netdev_tx_t bcm_transmit(struct sk_buff *skb, struct net_device *dev) |
| { |
| struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); |
| u16 qindex = skb_get_queue_mapping(skb); |
| |
| |
| if (Adapter->device_removed || !Adapter->LinkUpStatus) |
| goto drop; |
| |
| if (Adapter->TransferMode != IP_PACKET_ONLY_MODE) |
| goto drop; |
| |
| if (INVALID_QUEUE_INDEX == qindex) |
| goto drop; |
| |
| if (Adapter->PackInfo[qindex].uiCurrentPacketsOnHost >= |
| SF_MAX_ALLOWED_PACKETS_TO_BACKUP) |
| return NETDEV_TX_BUSY; |
| |
| /* Now Enqueue the packet */ |
| if (netif_msg_tx_queued(Adapter)) |
| pr_info(PFX "%s: enqueueing packet to queue %d\n", |
| dev->name, qindex); |
| |
| spin_lock(&Adapter->PackInfo[qindex].SFQueueLock); |
| Adapter->PackInfo[qindex].uiCurrentBytesOnHost += skb->len; |
| Adapter->PackInfo[qindex].uiCurrentPacketsOnHost++; |
| |
| *((B_UINT32 *) skb->cb + SKB_CB_LATENCY_OFFSET) = jiffies; |
| ENQUEUEPACKET(Adapter->PackInfo[qindex].FirstTxQueue, |
| Adapter->PackInfo[qindex].LastTxQueue, skb); |
| atomic_inc(&Adapter->TotalPacketCount); |
| spin_unlock(&Adapter->PackInfo[qindex].SFQueueLock); |
| |
| /* FIXME - this is racy and incorrect, replace with work queue */ |
| if (!atomic_read(&Adapter->TxPktAvail)) { |
| atomic_set(&Adapter->TxPktAvail, 1); |
| wake_up(&Adapter->tx_packet_wait_queue); |
| } |
| return NETDEV_TX_OK; |
| |
| drop: |
| dev_kfree_skb(skb); |
| return NETDEV_TX_OK; |
| } |
| |
| |
| |
| /** |
| @ingroup init_functions |
| Register other driver entry points with the kernel |
| */ |
| static const struct net_device_ops bcmNetDevOps = { |
| .ndo_open = bcm_open, |
| .ndo_stop = bcm_close, |
| .ndo_start_xmit = bcm_transmit, |
| .ndo_change_mtu = eth_change_mtu, |
| .ndo_set_mac_address = eth_mac_addr, |
| .ndo_validate_addr = eth_validate_addr, |
| .ndo_select_queue = bcm_select_queue, |
| }; |
| |
| static struct device_type wimax_type = { |
| .name = "wimax", |
| }; |
| |
| static int bcm_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) |
| { |
| cmd->supported = 0; |
| cmd->advertising = 0; |
| cmd->speed = SPEED_10000; |
| cmd->duplex = DUPLEX_FULL; |
| cmd->port = PORT_TP; |
| cmd->phy_address = 0; |
| cmd->transceiver = XCVR_INTERNAL; |
| cmd->autoneg = AUTONEG_DISABLE; |
| cmd->maxtxpkt = 0; |
| cmd->maxrxpkt = 0; |
| return 0; |
| } |
| |
| static void bcm_get_drvinfo(struct net_device *dev, |
| struct ethtool_drvinfo *info) |
| { |
| struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); |
| struct bcm_interface_adapter *psIntfAdapter = Adapter->pvInterfaceAdapter; |
| struct usb_device *udev = interface_to_usbdev(psIntfAdapter->interface); |
| |
| strcpy(info->driver, DRV_NAME); |
| strcpy(info->version, DRV_VERSION); |
| snprintf(info->fw_version, sizeof(info->fw_version), "%u.%u", |
| Adapter->uiFlashLayoutMajorVersion, |
| Adapter->uiFlashLayoutMinorVersion); |
| |
| usb_make_path(udev, info->bus_info, sizeof(info->bus_info)); |
| } |
| |
| static u32 bcm_get_link(struct net_device *dev) |
| { |
| struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); |
| |
| return Adapter->LinkUpStatus; |
| } |
| |
| static u32 bcm_get_msglevel(struct net_device *dev) |
| { |
| struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); |
| |
| return Adapter->msg_enable; |
| } |
| |
| static void bcm_set_msglevel(struct net_device *dev, u32 level) |
| { |
| struct bcm_mini_adapter *Adapter = GET_BCM_ADAPTER(dev); |
| |
| Adapter->msg_enable = level; |
| } |
| |
| static const struct ethtool_ops bcm_ethtool_ops = { |
| .get_settings = bcm_get_settings, |
| .get_drvinfo = bcm_get_drvinfo, |
| .get_link = bcm_get_link, |
| .get_msglevel = bcm_get_msglevel, |
| .set_msglevel = bcm_set_msglevel, |
| }; |
| |
| int register_networkdev(struct bcm_mini_adapter *Adapter) |
| { |
| struct net_device *net = Adapter->dev; |
| struct bcm_interface_adapter *IntfAdapter = Adapter->pvInterfaceAdapter; |
| struct usb_interface *udev = IntfAdapter->interface; |
| struct usb_device *xdev = IntfAdapter->udev; |
| |
| int result; |
| |
| net->netdev_ops = &bcmNetDevOps; |
| net->ethtool_ops = &bcm_ethtool_ops; |
| net->mtu = MTU_SIZE; /* 1400 Bytes */ |
| net->tx_queue_len = TX_QLEN; |
| net->flags |= IFF_NOARP; |
| |
| netif_carrier_off(net); |
| |
| SET_NETDEV_DEVTYPE(net, &wimax_type); |
| |
| /* Read the MAC Address from EEPROM */ |
| result = ReadMacAddressFromNVM(Adapter); |
| if (result != STATUS_SUCCESS) { |
| dev_err(&udev->dev, |
| PFX "Error in Reading the mac Address: %d", result); |
| return -EIO; |
| } |
| |
| result = register_netdev(net); |
| if (result) |
| return result; |
| |
| gblpnetdev = Adapter->dev; |
| |
| if (netif_msg_probe(Adapter)) |
| dev_info(&udev->dev, PFX "%s: register usb-%s-%s %pM\n", |
| net->name, xdev->bus->bus_name, xdev->devpath, |
| net->dev_addr); |
| |
| return 0; |
| } |
| |
| void unregister_networkdev(struct bcm_mini_adapter *Adapter) |
| { |
| struct net_device *net = Adapter->dev; |
| struct bcm_interface_adapter *IntfAdapter = Adapter->pvInterfaceAdapter; |
| struct usb_interface *udev = IntfAdapter->interface; |
| struct usb_device *xdev = IntfAdapter->udev; |
| |
| if (netif_msg_probe(Adapter)) |
| dev_info(&udev->dev, PFX "%s: unregister usb-%s%s\n", |
| net->name, xdev->bus->bus_name, xdev->devpath); |
| |
| unregister_netdev(Adapter->dev); |
| } |