/* * TX/RX related routines. */ static int rt2x00_start_xmit(struct rtskb *rtskb, struct rtnet_device *rtnet_dev) { struct rtwlan_device * rtwlan_dev = rtnetdev_priv(rtnet_dev); struct _rt2x00_core * core = rtwlan_priv(rtwlan_dev); u16 xmit_flags = 0x0000; u8 rate = 0x00; if (unlikely(rtskb)) { rate = core->config.bitrate; if(ieee80211_is_ofdm_rate(rate)) xmit_flags |= XMIT_OFDM; /* Check if the packet should be acknowledged */ if(core->rtwlan_dev->mode == RTWLAN_TXMODE_ACK) xmit_flags |= XMIT_ACK; if(core->handler->dev_xmit_packet(core, rtskb, rate, xmit_flags)) ERROR("Packet dropped !"); dev_kfree_rtskb(rtskb); } return 0; }
static void fec_stop(struct rtnet_device *ndev) { struct fec_enet_private *fep = rtnetdev_priv(ndev); const struct platform_device_id *id_entry = platform_get_device_id(fep->pdev); u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8); /* We cannot expect a graceful transmit stop without link !!! */ if (fep->link) { writel(1, fep->hwp + FEC_X_CNTRL); /* Graceful transmit stop */ udelay(10); if (!(readl(fep->hwp + FEC_IEVENT) & FEC_ENET_GRA)) printk("fec_stop : Graceful transmit stop did not complete !\n"); } /* Whack a reset. We should wait for this. */ writel(1, fep->hwp + FEC_ECNTRL); udelay(10); writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); /* We have to keep ENET enabled to have MII interrupt stay working */ if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { writel(2, fep->hwp + FEC_ECNTRL); writel(rmii_mode, fep->hwp + FEC_R_CNTRL); } }
void rt2x00_core_remove(struct rtnet_device * rtnet_dev) { struct rtwlan_device * rtwlan_dev = rtnetdev_priv(rtnet_dev); rtskb_pool_release(&rtwlan_dev->skb_pool); rt_unregister_rtnetdev(rtnet_dev); rt_rtdev_disconnect(rtnet_dev); rtdev_free(rtnet_dev); }
/* ------------------------------------------------------------------------- */ static void __inline__ fec_get_mac(struct rtnet_device *ndev) { struct fec_enet_private *fep = rtnetdev_priv(ndev); struct fec_platform_data *pdata = fep->pdev->dev.platform_data; unsigned char *iap, tmpaddr[ETH_ALEN]; /* * try to get mac address in following order: * * 1) module parameter via kernel command line in form * fec.macaddr=0x00,0x04,0x9f,0x01,0x30,0xe0 */ iap = macaddr; #ifdef CONFIG_OF /* * 2) from device tree data */ if (!is_valid_ether_addr(iap)) { struct device_node *np = fep->pdev->dev.of_node; if (np) { const char *mac = of_get_mac_address(np); if (mac) iap = (unsigned char *) mac; } } #endif /* * 3) from flash or fuse (via platform data) */ if (!is_valid_ether_addr(iap)) { #ifdef CONFIG_M5272 if (FEC_FLASHMAC) iap = (unsigned char *)FEC_FLASHMAC; #else if (pdata) iap = (unsigned char *)&pdata->mac; #endif } /* * 4) FEC mac registers set by bootloader */ if (!is_valid_ether_addr(iap)) { *((unsigned long *) &tmpaddr[0]) = be32_to_cpu(readl(fep->hwp + FEC_ADDR_LOW)); *((unsigned short *) &tmpaddr[4]) = be16_to_cpu(readl(fep->hwp + FEC_ADDR_HIGH) >> 16); iap = &tmpaddr[0]; }
static void rt2x00_interrupt_rxdone(struct _data_ring * ring, nanosecs_t *time_stamp) { struct _rt2x00_pci * rt2x00pci = rt2x00_priv(ring->device); struct rtnet_device * rtnet_dev = ring->device->rtnet_dev; struct rtwlan_device * rtwlan = rtnetdev_priv(rtnet_dev); struct _rxd * rxd = NULL; struct rtskb * rtskb; void * data = NULL; u16 size = 0x0000; /* u16 rssi = 0x0000; */ while(1){ rxd = DESC_ADDR(ring); data = DATA_ADDR(ring); if(rt2x00_get_field32(rxd->word0, RXD_W0_OWNER_NIC)) break; size = rt2x00_get_field32(rxd->word0, RXD_W0_DATABYTE_COUNT); /* rssi = rt2x00_get_field32(rxd->word2, RXD_W2_RSSI); */ /* prepare rtskb */ rtskb = dev_alloc_rtskb(size + NET_IP_ALIGN, &rtwlan->skb_pool); if(!rtskb){ ERROR("Couldn't allocate rtskb, packet dropped.\n"); break; } rtskb->rtdev = rtnet_dev; rtskb->time_stamp = *time_stamp; rtskb_reserve(rtskb, NET_IP_ALIGN); memcpy(rtskb->data, data, size); rtskb_put(rtskb, size); /* give incoming frame to rtwlan stack */ rtwlan_rx(rtskb, rtnet_dev); /* forward rtskb to rtnet */ rtnetif_rx(rtskb); rtwlan->stats.rx_packets++; rt2x00_set_field32(&rxd->word0, RXD_W0_OWNER_NIC, 1); rt2x00_ring_index_inc(&rt2x00pci->rx); } }
/* * Interrupt routines. * rt2x00_interrupt_txdone processes all transmitted packetss results. * rt2x00_interrupt_rxdone processes all received rx packets. */ static void rt2x00_interrupt_txdone(struct _data_ring * ring) { struct rtwlan_device * rtwlan = rtnetdev_priv(ring->device->rtnet_dev); struct _txd *txd = NULL; u8 tx_result = 0x00; /* u8 retry_count = 0x00; */ do{ txd = DESC_ADDR_DONE(ring); if(rt2x00_get_field32(txd->word0, TXD_W0_OWNER_NIC) || !rt2x00_get_field32(txd->word0, TXD_W0_VALID)) break; if(ring->ring_type == RING_TX){ tx_result = rt2x00_get_field32(txd->word0, TXD_W0_RESULT); /* retry_count = rt2x00_get_field32(txd->word0, TXD_W0_RETRY_COUNT); */ switch(tx_result) { case TX_SUCCESS: rtwlan->stats.tx_packets++; break; case TX_SUCCESS_RETRY: rtwlan->stats.tx_retry++; break; case TX_FAIL_RETRY: DEBUG("TX_FAIL_RETRY.\n"); break; case TX_FAIL_INVALID: DEBUG("TX_FAIL_INVALID.\n"); break; case TX_FAIL_OTHER: DEBUG("TX_FAIL_OTHER.\n"); break; default: DEBUG("Unknown tx result.\n"); } } rt2x00_set_field32(&txd->word0, TXD_W0_VALID, 0); rt2x00_ring_index_done_inc(ring); }while(!rt2x00_ring_empty(ring)); }
static int fec_enet_interrupt(rtdm_irq_t *irq_handle) { struct rtnet_device *ndev = rtdm_irq_get_arg(irq_handle, struct rtnet_device); /* RTnet */ struct fec_enet_private *fep = rtnetdev_priv(ndev); uint int_events; irqreturn_t ret = RTDM_IRQ_NONE; /* RTnet */ nanosecs_abs_t time_stamp = rtdm_clock_read(); int packets = 0; do { int_events = readl(fep->hwp + FEC_IEVENT); writel(int_events, fep->hwp + FEC_IEVENT); if (int_events & FEC_ENET_RXF) { ret = RTDM_IRQ_HANDLED; fec_enet_rx(ndev, &packets, &time_stamp); } /* Transmit OK, or non-fatal error. Update the buffer * descriptors. FEC handles all errors, we just discover * them as part of the transmit process. */ if (int_events & FEC_ENET_TXF) { ret = RTDM_IRQ_HANDLED; fec_enet_tx(ndev); } if (int_events & FEC_ENET_MII) { ret = RTDM_IRQ_HANDLED; rtdm_nrtsig_pend(&fep->mdio_done_sig); } } while (int_events); if (packets > 0) rt_mark_stack_mgr(ndev); return ret; }
int rtwlan_rx(struct rtskb * rtskb, struct rtnet_device * rtnet_dev) { struct rtwlan_device * rtwlan = rtnetdev_priv(rtnet_dev); struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)rtskb->data; u16 fc = le16_to_cpu(hdr->frame_ctl); switch(rtwlan->mode) { case RTWLAN_MODE_RAW: case RTWLAN_MODE_ACK: rtskb_pull(rtskb, ieee80211_get_hdrlen(fc)); rtskb->protocol = rt_eth_type_trans (rtskb, rtnet_dev); break; case RTWLAN_MODE_MON: rtskb->mac.raw = rtskb->data; rtcap_mark_incoming(rtskb); break; } return 0; }
/*** * rt2x00_close * @rtdev */ static int rt2x00_close (struct rtnet_device *rtnet_dev) { struct rtwlan_device * rtwlan_dev = rtnetdev_priv(rtnet_dev); struct _rt2x00_core * core = rtwlan_priv(rtwlan_dev); DEBUG("Start.\n"); if(!test_and_clear_bit(DEVICE_ENABLED, &core->flags)){ ERROR("device already disabled.\n"); return -EBUSY; } rt2x00_radio_off(core); rtnetif_stop_queue(rtnet_dev); rt_stack_disconnect(rtnet_dev); RTNET_MOD_DEC_USE_COUNT; return 0; }
int rt2x00_interrupt(rtdm_irq_t *irq_handle) { nanosecs_t time_stamp = rtdm_clock_read(); struct rtnet_device * rtnet_dev = rtdm_irq_get_arg(irq_handle, struct rtnet_device); struct _rt2x00_device * device = rtwlan_priv(rtnet_dev); struct _rt2x00_pci * rt2x00pci = rt2x00_priv(device); struct rtwlan_device * rtwlan = rtnetdev_priv(rtnet_dev); unsigned int old_packet_cnt = rtwlan->stats.rx_packets; u32 reg = 0x00000000; rtdm_lockctx_t context; rtdm_lock_get_irqsave(&rtwlan->lock, context); rt2x00_register_read(rt2x00pci, CSR7, ®); rt2x00_register_write(rt2x00pci, CSR7, reg); if(!reg) return RTDM_IRQ_NONE; if(rt2x00_get_field32(reg, CSR7_TBCN_EXPIRE)) /* Beacon timer expired interrupt. */ DEBUG("Beacon timer expired.\n"); if(rt2x00_get_field32(reg, CSR7_RXDONE)) /* Rx ring done interrupt. */ rt2x00_interrupt_rxdone(&rt2x00pci->rx, &time_stamp); if(rt2x00_get_field32(reg, CSR7_TXDONE_ATIMRING)) /* Atim ring transmit done interrupt. */ DEBUG("AtimTxDone.\n"); if(rt2x00_get_field32(reg, CSR7_TXDONE_PRIORING)) /* Priority ring transmit done interrupt. */ DEBUG("PrioTxDone.\n"); if(rt2x00_get_field32(reg, CSR7_TXDONE_TXRING)) /* Tx ring transmit done interrupt. */ rt2x00_interrupt_txdone(&rt2x00pci->tx); if (old_packet_cnt != rtwlan->stats.rx_packets) rt_mark_stack_mgr(rtnet_dev); rtdm_lock_put_irqrestore(&rtwlan->lock, context); return RTDM_IRQ_HANDLED; }
/*** * rt2x00_open * @rtdev */ static int rt2x00_open (struct rtnet_device *rtnet_dev) { struct rtwlan_device * rtwlan_dev = rtnetdev_priv(rtnet_dev); struct _rt2x00_core * core = rtwlan_priv(rtwlan_dev); int status = 0x00000000; DEBUG("Start.\n"); if(test_and_set_bit(DEVICE_ENABLED, &core->flags)){ ERROR("device already enabled.\n"); return -EBUSY; } /* * Start rtnet interface. */ rt_stack_connect(rtnet_dev, &STACK_manager); status = rt2x00_radio_on(core); if(status){ clear_bit(DEVICE_ENABLED, &core->flags); ERROR("Couldn't activate radio.\n"); return status; } core->config.led_status = 1; core->config.update_flags |= UPDATE_LED_STATUS; rt2x00_update_config(core); rtnetif_start_queue(rtnet_dev); RTNET_MOD_INC_USE_COUNT; DEBUG("Exit success.\n"); return 0; }
int rtwlan_tx(struct rtskb *rtskb, struct rtnet_device *rtnet_dev) { struct rtwlan_device * rtwlan = rtnetdev_priv(rtnet_dev); struct ieee80211_hdr_3addr header = { /* Ensure zero initialized */ .duration_id = 0, .seq_ctl = 0 }; u8 dest[ETH_ALEN], src[ETH_ALEN]; /* Save source and destination addresses */ memcpy(dest, rtskb->data, ETH_ALEN); memcpy(src, rtskb->data + ETH_ALEN, ETH_ALEN); /* Generate ieee80211 compatible header */ memcpy(header.addr3, src, ETH_ALEN); /* BSSID */ memcpy(header.addr2, src, ETH_ALEN); /* SA */ memcpy(header.addr1, dest, ETH_ALEN); /* DA */ /* Frame Control */ switch(rtwlan->mode) { case RTWLAN_MODE_RAW: header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_BEACON); break; case RTWLAN_MODE_ACK: header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_DATA); break; default: return -1; } memcpy(rtskb_push(rtskb, IEEE80211_3ADDR_LEN), &header, IEEE80211_3ADDR_LEN); return 0; } EXPORT_SYMBOL(rtwlan_tx); /** * rtalloc_wlandev - Allocates and sets up a wlan device * @sizeof_priv: size of additional driver-private structure to * be allocated for this wlan device * * Fill in the fields of the device structure with wlan-generic * values. Basically does everything except registering the device. * * A 32-byte alignment is enforced for the private data area. */ struct rtnet_device * rtwlan_alloc_dev(int sizeof_priv) { struct rtnet_device *rtnet_dev; RTWLAN_DEBUG("Start.\n"); rtnet_dev = rt_alloc_etherdev(sizeof(struct rtwlan_device) + sizeof_priv); if (!rtnet_dev) return NULL; rtdev_alloc_name(rtnet_dev, "rtwlan%d"); return rtnet_dev; } EXPORT_SYMBOL(rtwlan_alloc_dev); int rtwlan_ioctl(struct rtnet_device * rtdev, unsigned int request, unsigned long arg) { struct rtwlan_cmd cmd; int ret=0; if (copy_from_user(&cmd, (void *)arg, sizeof(cmd)) != 0) return -EFAULT; switch(request) { case IOC_RTWLAN_IFINFO: if (cmd.args.info.ifindex > 0) rtdev = rtdev_get_by_index(cmd.args.info.ifindex); else rtdev = rtdev_get_by_name(cmd.head.if_name); if (rtdev == NULL) return -ENODEV; if (down_interruptible(&rtdev->nrt_lock)) { rtdev_dereference(rtdev); return -ERESTARTSYS; } if (rtdev->do_ioctl) ret = rtdev->do_ioctl(rtdev, request, &cmd); else ret = -ENORTWLANDEV; memcpy(cmd.head.if_name, rtdev->name, IFNAMSIZ); cmd.args.info.ifindex = rtdev->ifindex; cmd.args.info.flags = rtdev->flags; up(&rtdev->nrt_lock); rtdev_dereference(rtdev); break; case IOC_RTWLAN_MODE: case IOC_RTWLAN_BITRATE: case IOC_RTWLAN_CHANNEL: case IOC_RTWLAN_TXPOWER: case IOC_RTWLAN_DROPBCAST: case IOC_RTWLAN_DROPMCAST: case IOC_RTWLAN_REGREAD: case IOC_RTWLAN_REGWRITE: case IOC_RTWLAN_BBPWRITE: case IOC_RTWLAN_BBPREAD: case IOC_RTWLAN_BBPSENS: if (down_interruptible(&rtdev->nrt_lock)) return -ERESTARTSYS; if (rtdev->do_ioctl) ret = rtdev->do_ioctl(rtdev, request, &cmd); else ret = -ENORTWLANDEV; up(&rtdev->nrt_lock); break; default: ret = -ENOTTY; } if (copy_to_user((void *)arg, &cmd, sizeof(cmd)) != 0) return -EFAULT; return ret; } struct rtnet_ioctls rtnet_wlan_ioctls = { service_name: "rtwlan ioctl", ioctl_type: RTNET_IOC_TYPE_RTWLAN, handler: rtwlan_ioctl };
/* During a receive, the cur_rx points to the current incoming buffer. * When we update through the ring, if the next incoming buffer has * not been given to the system, we just set the empty indicator, * effectively tossing the packet. */ static void fec_enet_rx(struct rtnet_device *ndev, int *packets, nanosecs_abs_t *time_stamp) { struct fec_enet_private *fep = rtnetdev_priv(ndev); const struct platform_device_id *id_entry = platform_get_device_id(fep->pdev); struct bufdesc *bdp; unsigned short status; struct rtskb *skb; ushort pkt_len; __u8 *data; #ifdef CONFIG_M532x flush_cache_all(); #endif rtdm_lock_get(&fep->hw_lock); /* First, grab all of the stats for the incoming packet. * These get messed up if we get called due to a busy condition. */ bdp = fep->cur_rx; while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) { /* Since we have allocated space to hold a complete frame, * the last indicator should be set. */ if ((status & BD_ENET_RX_LAST) == 0) printk("FEC ENET: rcv is not +last\n"); if (!fep->opened) goto rx_processing_done; /* Check for errors. */ if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) { fep->stats.rx_errors++; if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) { /* Frame too long or too short. */ fep->stats.rx_length_errors++; } if (status & BD_ENET_RX_NO) /* Frame alignment */ fep->stats.rx_frame_errors++; if (status & BD_ENET_RX_CR) /* CRC Error */ fep->stats.rx_crc_errors++; if (status & BD_ENET_RX_OV) /* FIFO overrun */ fep->stats.rx_fifo_errors++; } /* Report late collisions as a frame error. * On this error, the BD is closed, but we don't know what we * have in the buffer. So, just drop this frame on the floor. */ if (status & BD_ENET_RX_CL) { fep->stats.rx_errors++; fep->stats.rx_frame_errors++; goto rx_processing_done; } /* Process the incoming frame. */ fep->stats.rx_packets++; pkt_len = bdp->cbd_datlen; fep->stats.rx_bytes += pkt_len; data = (__u8*)__va(bdp->cbd_bufaddr); dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, FEC_ENET_TX_FRSIZE, DMA_FROM_DEVICE); if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) swap_buffer(data, pkt_len); /* This does 16 byte alignment, exactly what we need. * The packet length includes FCS, but we don't want to * include that when passing upstream as it messes up * bridging applications. */ skb = dev_alloc_rtskb(pkt_len - 4 + NET_IP_ALIGN, &fep->skb_pool); /* RTnet */ if (unlikely(!skb)) { printk("%s: Memory squeeze, dropping packet.\n", ndev->name); fep->stats.rx_dropped++; } else { rtskb_reserve(skb, NET_IP_ALIGN); rtskb_put(skb, pkt_len - 4); /* Make room */ memcpy(skb->data, data, pkt_len - 4); skb->protocol = rt_eth_type_trans(skb, ndev); skb->rtdev = ndev; skb->time_stamp = *time_stamp; rtnetif_rx(skb); (*packets)++; /* RTnet */ } bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, data, FEC_ENET_TX_FRSIZE, DMA_FROM_DEVICE); rx_processing_done: /* Clear the status flags for this buffer */ status &= ~BD_ENET_RX_STATS; /* Mark the buffer empty */ status |= BD_ENET_RX_EMPTY; bdp->cbd_sc = status; /* Update BD pointer to next entry */ if (status & BD_ENET_RX_WRAP) bdp = fep->rx_bd_base; else bdp++; /* Doing this here will keep the FEC running while we process * incoming frames. On a heavily loaded network, we should be * able to keep up at the expense of system resources. */ writel(0, fep->hwp + FEC_R_DES_ACTIVE); } fep->cur_rx = bdp; rtdm_lock_put(&fep->hw_lock); }
/* This function is called to start or restart the FEC during a link * change. This only happens when switching between half and full * duplex. */ static void fec_restart(struct rtnet_device *ndev, int duplex) { struct fec_enet_private *fep = rtnetdev_priv(ndev); const struct platform_device_id *id_entry = platform_get_device_id(fep->pdev); int i; u32 temp_mac[2]; u32 rcntl = OPT_FRAME_SIZE | 0x04; u32 ecntl = 0x2; /* ETHEREN */ /* Whack a reset. We should wait for this. */ writel(1, fep->hwp + FEC_ECNTRL); udelay(10); /* * enet-mac reset will reset mac address registers too, * so need to reconfigure it. */ if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { memcpy(&temp_mac, ndev->dev_addr, ETH_ALEN); writel(cpu_to_be32(temp_mac[0]), fep->hwp + FEC_ADDR_LOW); writel(cpu_to_be32(temp_mac[1]), fep->hwp + FEC_ADDR_HIGH); } /* Clear any outstanding interrupt. */ writel(0xffc00000, fep->hwp + FEC_IEVENT); /* Reset all multicast. */ writel(0, fep->hwp + FEC_GRP_HASH_TABLE_HIGH); writel(0, fep->hwp + FEC_GRP_HASH_TABLE_LOW); #ifndef CONFIG_M5272 writel(0, fep->hwp + FEC_HASH_TABLE_HIGH); writel(0, fep->hwp + FEC_HASH_TABLE_LOW); #endif /* Set maximum receive buffer size. */ writel(PKT_MAXBLR_SIZE, fep->hwp + FEC_R_BUFF_SIZE); /* Set receive and transmit descriptor base. */ writel(fep->bd_dma, fep->hwp + FEC_R_DES_START); writel((unsigned long)fep->bd_dma + sizeof(struct bufdesc) * RX_RING_SIZE, fep->hwp + FEC_X_DES_START); fep->dirty_tx = fep->cur_tx = fep->tx_bd_base; fep->cur_rx = fep->rx_bd_base; /* Reset SKB transmit buffers. */ fep->skb_cur = fep->skb_dirty = 0; for (i = 0; i <= TX_RING_MOD_MASK; i++) { if (fep->tx_skbuff[i]) { dev_kfree_rtskb(fep->tx_skbuff[i]); fep->tx_skbuff[i] = NULL; } } /* Enable MII mode */ if (duplex) { /* FD enable */ writel(0x04, fep->hwp + FEC_X_CNTRL); } else { /* No Rcv on Xmit */ rcntl |= 0x02; writel(0x0, fep->hwp + FEC_X_CNTRL); } fep->full_duplex = duplex; /* Set MII speed */ writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED); /* * The phy interface and speed need to get configured * differently on enet-mac. */ if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { /* Enable flow control and length check */ rcntl |= 0x40000000 | 0x00000020; /* RGMII, RMII or MII */ if (fep->phy_interface == PHY_INTERFACE_MODE_RGMII) rcntl |= (1 << 6); else if (fep->phy_interface == PHY_INTERFACE_MODE_RMII) rcntl |= (1 << 8); else rcntl &= ~(1 << 8); /* 1G, 100M or 10M */ if (fep->phy_dev) { if (fep->phy_dev->speed == SPEED_1000) ecntl |= (1 << 5); else if (fep->phy_dev->speed == SPEED_100) rcntl &= ~(1 << 9); else rcntl |= (1 << 9); } } else { #ifdef FEC_MIIGSK_ENR if (id_entry->driver_data & FEC_QUIRK_USE_GASKET) { u32 cfgr; /* disable the gasket and wait */ writel(0, fep->hwp + FEC_MIIGSK_ENR); while (readl(fep->hwp + FEC_MIIGSK_ENR) & 4) udelay(1); /* * configure the gasket: * RMII, 50 MHz, no loopback, no echo * MII, 25 MHz, no loopback, no echo */ cfgr = (fep->phy_interface == PHY_INTERFACE_MODE_RMII) ? BM_MIIGSK_CFGR_RMII : BM_MIIGSK_CFGR_MII; if (fep->phy_dev && fep->phy_dev->speed == SPEED_10) cfgr |= BM_MIIGSK_CFGR_FRCONT_10M; writel(cfgr, fep->hwp + FEC_MIIGSK_CFGR); /* re-enable the gasket */ writel(2, fep->hwp + FEC_MIIGSK_ENR); } #endif } writel(rcntl, fep->hwp + FEC_R_CNTRL); if (id_entry->driver_data & FEC_QUIRK_ENET_MAC) { /* enable ENET endian swap */ ecntl |= (1 << 8); /* enable ENET store and forward mode */ writel(1 << 8, fep->hwp + FEC_X_WMRK); } /* And last, enable the transmit and receive processing */ writel(ecntl, fep->hwp + FEC_ECNTRL); writel(0, fep->hwp + FEC_R_DES_ACTIVE); /* Enable interrupts we wish to service */ writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK); }
static int fec_enet_start_xmit(struct rtskb *skb, struct rtnet_device *ndev) { struct fec_enet_private *fep = rtnetdev_priv(ndev); const struct platform_device_id *id_entry = platform_get_device_id(fep->pdev); struct bufdesc *bdp; void *bufaddr; unsigned short status; unsigned long context; if (!fep->link) { /* Link is down or autonegotiation is in progress. */ printk("%s: tx link down!.\n", ndev->name); rtnetif_stop_queue(ndev); return 1; /* RTnet: will call kfree_rtskb() */ } rtdm_lock_get_irqsave(&fep->hw_lock, context); /* RTnet */ if (skb->xmit_stamp) *skb->xmit_stamp = cpu_to_be64(rtdm_clock_read() + *skb->xmit_stamp); /* Fill in a Tx ring entry */ bdp = fep->cur_tx; status = bdp->cbd_sc; if (status & BD_ENET_TX_READY) { /* Ooops. All transmit buffers are full. Bail out. * This should not happen, since ndev->tbusy should be set. */ printk("%s: tx queue full!.\n", ndev->name); rtdm_lock_put_irqrestore(&fep->hw_lock, context); return 1; /* RTnet: will call kfree_rtskb() */ } /* Clear all of the status flags */ status &= ~BD_ENET_TX_STATS; /* Set buffer length and buffer pointer */ bufaddr = skb->data; bdp->cbd_datlen = skb->len; /* * On some FEC implementations data must be aligned on * 4-byte boundaries. Use bounce buffers to copy data * and get it aligned. Ugh. */ if (((unsigned long) bufaddr) & FEC_ALIGNMENT) { unsigned int index; index = bdp - fep->tx_bd_base; memcpy(fep->tx_bounce[index], skb->data, skb->len); bufaddr = fep->tx_bounce[index]; } /* * Some design made an incorrect assumption on endian mode of * the system that it's running on. As the result, driver has to * swap every frame going to and coming from the controller. */ if (id_entry->driver_data & FEC_QUIRK_SWAP_FRAME) swap_buffer(bufaddr, skb->len); /* Save skb pointer */ fep->tx_skbuff[fep->skb_cur] = skb; fep->stats.tx_bytes += skb->len; fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK; /* Push the data cache so the CPM does not get stale memory * data. */ bdp->cbd_bufaddr = dma_map_single(&fep->pdev->dev, bufaddr, FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE); /* Send it on its way. Tell FEC it's ready, interrupt when done, * it's the last BD of the frame, and to put the CRC on the end. */ status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR | BD_ENET_TX_LAST | BD_ENET_TX_TC); bdp->cbd_sc = status; /* Trigger transmission start */ writel(0, fep->hwp + FEC_X_DES_ACTIVE); /* If this was the last BD in the ring, start at the beginning again. */ if (status & BD_ENET_TX_WRAP) bdp = fep->tx_bd_base; else bdp++; if (bdp == fep->dirty_tx) { fep->tx_full = 1; rtnetif_stop_queue(ndev); } fep->cur_tx = bdp; rtdm_lock_put_irqrestore(&fep->hw_lock, context); return NETDEV_TX_OK; }
struct rtnet_device * rt2x00_core_probe(struct _rt2x00_dev_handler * handler, void * priv, u32 sizeof_dev) { struct rtnet_device * rtnet_dev = NULL; struct _rt2x00_core * core = NULL; struct rtwlan_device * rtwlan_dev = NULL; static int cards_found = -1; int err; DEBUG("Start.\n"); cards_found++; if (cards[cards_found] == 0) goto exit; rtnet_dev = rtwlan_alloc_dev(sizeof_dev + sizeof(*core)); if(!rtnet_dev) goto exit; rt_rtdev_connect(rtnet_dev, &RTDEV_manager); RTNET_SET_MODULE_OWNER(rtnet_dev); rtnet_dev->vers = RTDEV_VERS_2_0; rtwlan_dev = rtnetdev_priv(rtnet_dev); memset(rtwlan_dev, 0x00, sizeof(*rtwlan_dev)); core = rtwlan_priv(rtwlan_dev); memset(core, 0x00, sizeof(*core)); core->rtwlan_dev = rtwlan_dev; core->handler = handler; core->priv = (void*)core + sizeof(*core); core->rtnet_dev = rtnet_dev; if (rtskb_pool_init(&core->rtwlan_dev->skb_pool, RX_ENTRIES*2) < RX_ENTRIES*2) { rtskb_pool_release(&core->rtwlan_dev->skb_pool); ERROR("rtskb_pool_init failed.\n"); goto exit; } /* Set configuration default values. */ rt2x00_init_config(core); if(core->handler->dev_probe && core->handler->dev_probe(core, priv)){ ERROR("device probe failed.\n"); goto exit; } INFO("Device " MAC_FMT " detected.\n", MAC_ARG(rtnet_dev->dev_addr)); rtwlan_dev->hard_start_xmit = rt2x00_start_xmit; rtnet_dev->open = &rt2x00_open; rtnet_dev->stop = &rt2x00_close; rtnet_dev->do_ioctl = &rt2x00_ioctl; rtnet_dev->hard_header = &rt_eth_header; if ((err = rt_register_rtnetdev(rtnet_dev)) != 0) { rtdev_free(rtnet_dev); ERROR("rtnet_device registration failed.\n"); printk("err=%d\n", err); goto exit_dev_remove; } set_bit(DEVICE_AWAKE, &core->flags); return rtnet_dev; exit_dev_remove: if(core->handler->dev_remove) core->handler->dev_remove(core); exit: return NULL; }
static void fec_enet_tx(struct rtnet_device *ndev) { struct fec_enet_private *fep; struct bufdesc *bdp; unsigned short status; struct rtskb *skb; fep = rtnetdev_priv(ndev); rtdm_lock_get(&fep->hw_lock); bdp = fep->dirty_tx; while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) { if (bdp == fep->cur_tx && fep->tx_full == 0) break; dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr, FEC_ENET_TX_FRSIZE, DMA_TO_DEVICE); bdp->cbd_bufaddr = 0; skb = fep->tx_skbuff[fep->skb_dirty]; /* Check for errors. */ if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) { fep->stats.tx_errors++; if (status & BD_ENET_TX_HB) /* No heartbeat */ fep->stats.tx_heartbeat_errors++; if (status & BD_ENET_TX_LC) /* Late collision */ fep->stats.tx_window_errors++; if (status & BD_ENET_TX_RL) /* Retrans limit */ fep->stats.tx_aborted_errors++; if (status & BD_ENET_TX_UN) /* Underrun */ fep->stats.tx_fifo_errors++; if (status & BD_ENET_TX_CSL) /* Carrier lost */ fep->stats.tx_carrier_errors++; } else { fep->stats.tx_packets++; } if (status & BD_ENET_TX_READY) printk("HEY! Enet xmit interrupt and TX_READY.\n"); /* Deferred means some collisions occurred during transmit, * but we eventually sent the packet OK. */ if (status & BD_ENET_TX_DEF) fep->stats.collisions++; /* Free the sk buffer associated with this last transmit */ dev_kfree_rtskb(skb); /* RTnet */ fep->tx_skbuff[fep->skb_dirty] = NULL; fep->skb_dirty = (fep->skb_dirty + 1) & TX_RING_MOD_MASK; /* Update pointer to next buffer descriptor to be transmitted */ if (status & BD_ENET_TX_WRAP) bdp = fep->tx_bd_base; else bdp++; /* Since we have freed up a buffer, the ring is no longer full */ if (fep->tx_full) { fep->tx_full = 0; if (rtnetif_queue_stopped(ndev)) rtnetif_wake_queue(ndev); } } fep->dirty_tx = bdp; rtdm_lock_put(&fep->hw_lock); }
/* * user space io handler */ static int rt2x00_ioctl(struct rtnet_device * rtnet_dev, unsigned int request, void * arg) { struct rtwlan_device * rtwlan_dev = rtnetdev_priv(rtnet_dev); struct _rt2x00_core * core = rtwlan_priv(rtwlan_dev); struct rtwlan_cmd * cmd; u8 rate, dsss_rate, ofdm_rate; u32 address, value; cmd = (struct rtwlan_cmd *)arg; switch(request) { case IOC_RTWLAN_IFINFO: cmd->args.info.bitrate = core->config.bitrate; cmd->args.info.channel = core->config.channel; cmd->args.info.retry = core->config.short_retry; cmd->args.info.txpower = core->config.txpower; cmd->args.info.bbpsens = core->config.bbpsens; cmd->args.info.mode = core->rtwlan_dev->mode; cmd->args.info.rx_packets = core->rtwlan_dev->stats.rx_packets; cmd->args.info.tx_packets = core->rtwlan_dev->stats.tx_packets; cmd->args.info.tx_retry = core->rtwlan_dev->stats.tx_retry; cmd->args.info.autoresponder = core->config.config_flags & CONFIG_AUTORESP ? 1 : 0; cmd->args.info.dropbcast = core->config.config_flags & CONFIG_DROP_BCAST ? 1 : 0; cmd->args.info.dropmcast = core->config.config_flags & CONFIG_DROP_MCAST ? 1 : 0; DEBUG("rtwlan_dev->mode=%d\n", rtwlan_dev->mode); break; case IOC_RTWLAN_BITRATE: rate = cmd->args.set.bitrate; ofdm_rate = ieee80211_is_ofdm_rate(rate); dsss_rate = ieee80211_is_dsss_rate(rate); DEBUG("bitrate=%d\n", rate); if(!(dsss_rate ^ ofdm_rate)) NOTICE("Rate %d is not DSSS and not OFDM.\n", rate); core->config.bitrate = rate; core->config.update_flags |= UPDATE_BITRATE; break; case IOC_RTWLAN_CHANNEL: DEBUG("channel=%d\n", cmd->args.set.channel); core->config.channel = cmd->args.set.channel; core->config.update_flags |= UPDATE_CHANNEL; break; case IOC_RTWLAN_RETRY: core->config.short_retry = cmd->args.set.retry; core->config.update_flags |= UPDATE_RETRY; break; case IOC_RTWLAN_TXPOWER: core->config.txpower = cmd->args.set.txpower; core->config.update_flags |= UPDATE_TXPOWER; break; case IOC_RTWLAN_AUTORESP: if(cmd->args.set.autoresponder) core->config.config_flags |= CONFIG_AUTORESP; else core->config.config_flags &= ~CONFIG_AUTORESP; core->config.update_flags |= UPDATE_AUTORESP; break; case IOC_RTWLAN_DROPBCAST: if(cmd->args.set.dropbcast) core->config.config_flags |= CONFIG_DROP_BCAST; else core->config.config_flags &= ~CONFIG_DROP_BCAST; core->config.update_flags |= UPDATE_PACKET_FILTER; break; case IOC_RTWLAN_DROPMCAST: if(cmd->args.set.dropmcast) core->config.config_flags |= CONFIG_DROP_MCAST; else core->config.config_flags &= ~CONFIG_DROP_MCAST; core->config.update_flags |= UPDATE_PACKET_FILTER; break; case IOC_RTWLAN_TXMODE: core->rtwlan_dev->mode = cmd->args.set.mode; break; case IOC_RTWLAN_BBPSENS: value = cmd->args.set.bbpsens; if(value < 0) value = 0; if(value > 127) value = 127; core->config.bbpsens = value; core->config.update_flags |= UPDATE_BBPSENS; break; case IOC_RTWLAN_REGREAD: case IOC_RTWLAN_BBPREAD: address = cmd->args.reg.address; core->handler->dev_register_access(core, request, address, &value); cmd->args.reg.value = value; break; case IOC_RTWLAN_REGWRITE: case IOC_RTWLAN_BBPWRITE: address = cmd->args.reg.address; value = cmd->args.reg.value; core->handler->dev_register_access(core, request, address, &value) ; break; default: ERROR("Unknown request!\n"); return -1; } if(request != IOC_RTWLAN_IFINFO) rt2x00_update_config(core); return 0; }