📄 ag7100.c
字号:
spin_unlock_irqrestore(&mac->mac_lock, flags); } netif_wake_queue(mac->mac_dev); } return reaped;}/* * allocate and init rings, descriptors etc. */static intag7100_tx_alloc(ag7100_mac_t *mac){ ag7100_ring_t *r = &mac->mac_txring; ag7100_desc_t *ds; int i, next; if (ag7100_ring_alloc(r, AG7100_TX_DESC_CNT)) return 1; ag7100_trc(r->ring_desc,"ring_desc"); ds = r->ring_desc; for(i = 0; i < r->ring_nelem; i++ ) { ag7100_trc_new(ds,"tx alloc ds"); next = (i == (r->ring_nelem - 1)) ? 0 : (i + 1); ds[i].next_desc = ag7100_desc_dma_addr(r, &ds[next]); ag7100_tx_own(&ds[i]); } return 0;}static intag7100_rx_alloc(ag7100_mac_t *mac){ ag7100_ring_t *r = &mac->mac_rxring; ag7100_desc_t *ds; int i, next, tail = r->ring_tail; ag7100_buffer_t *bf; if (ag7100_ring_alloc(r, AG7100_RX_DESC_CNT)) return 1; ag7100_trc(r->ring_desc,"ring_desc"); ds = r->ring_desc; for(i = 0; i < r->ring_nelem; i++ ) { next = (i == (r->ring_nelem - 1)) ? 0 : (i + 1); ds[i].next_desc = ag7100_desc_dma_addr(r, &ds[next]); } for (i = 0; i < AG7100_RX_DESC_CNT; i++) { bf = &r->ring_buffer[tail]; ds = &r->ring_desc[tail]; bf->buf_pkt = ag7100_buffer_alloc(); if (!bf->buf_pkt) goto error; dma_cache_inv((unsigned long)bf->buf_pkt->data, AG7100_RX_BUF_SIZE); ds->pkt_start_addr = virt_to_phys(bf->buf_pkt->data); ag7100_rx_give_to_dma(ds); ag7100_ring_incr(tail); } return 0;error: printk(MODULE_NAME ": unable to allocate rx\n"); ag7100_rx_free(mac); return 1;}static voidag7100_tx_free(ag7100_mac_t *mac){ ag7100_ring_release(mac, &mac->mac_txring); ag7100_ring_free(&mac->mac_txring);}static voidag7100_rx_free(ag7100_mac_t *mac){ ag7100_ring_release(mac, &mac->mac_rxring); ag7100_ring_free(&mac->mac_rxring);}static intag7100_ring_alloc(ag7100_ring_t *r, int count){ int desc_alloc_size, buf_alloc_size; desc_alloc_size = sizeof(ag7100_desc_t) * count; buf_alloc_size = sizeof(ag7100_buffer_t) * count; memset(r, 0, sizeof(ag7100_ring_t)); r->ring_buffer = (ag7100_buffer_t *)kmalloc(buf_alloc_size, GFP_KERNEL); printk("%s Allocated %d at 0x%lx\n",__func__,buf_alloc_size,(unsigned long) r->ring_buffer); if (!r->ring_buffer) { printk(MODULE_NAME ": unable to allocate buffers\n"); return 1; } r->ring_desc = (ag7100_desc_t *)dma_alloc_coherent(NULL, desc_alloc_size, &r->ring_desc_dma, GFP_DMA); if (! r->ring_desc) { printk(MODULE_NAME ": unable to allocate coherent descs\n"); kfree(r->ring_buffer); printk("%s Freeing at 0x%lx\n",__func__,(unsigned long) r->ring_buffer); return 1; } memset(r->ring_buffer, 0, buf_alloc_size); memset(r->ring_desc, 0, desc_alloc_size); r->ring_nelem = count; return 0;}static voidag7100_ring_release(ag7100_mac_t *mac, ag7100_ring_t *r){ int i; for(i = 0; i < r->ring_nelem; i++) if (r->ring_buffer[i].buf_pkt) ag7100_buffer_free(r->ring_buffer[i].buf_pkt);}static voidag7100_ring_free(ag7100_ring_t *r){ dma_free_coherent(NULL, sizeof(ag7100_desc_t)*r->ring_nelem, r->ring_desc, r->ring_desc_dma); kfree(r->ring_buffer); printk("%s Freeing at 0x%lx\n",__func__,(unsigned long) r->ring_buffer);}/* * Error timers */static voidag7100_oom_timer(unsigned long data){ ag7100_mac_t *mac = (ag7100_mac_t *)data; int val; ag7100_trc(data,"data"); ag7100_rx_replenish(mac); if (ag7100_rx_ring_full(mac)) { val = mod_timer(&mac->mac_oom_timer, jiffies+1); assert(!val); } else netif_rx_schedule(mac->mac_dev);}static voidag7100_tx_timeout(struct net_device *dev){ ag7100_mac_t *mac = (ag7100_mac_t *)dev->priv; ag7100_trc(dev,"dev"); printk("%s\n",__func__); /* * Do the reset outside of interrupt context */ schedule_work(&mac->mac_tx_timeout);}static voidag7100_tx_timeout_task(ag7100_mac_t *mac){ ag7100_trc(mac,"mac"); ag7100_stop(mac->mac_dev); ag7100_open(mac->mac_dev);}static voidag7100_get_default_macaddr(ag7100_mac_t *mac, u8 *mac_addr){ /* Use MAC address stored in Flash */ u8 *eep_mac_addr = (mac->mac_unit) ? AR7100_EEPROM_GE1_MAC_ADDR: AR7100_EEPROM_GE0_MAC_ADDR; printk(MODULE_NAME "CHH: Mac address for unit %d\n",mac->mac_unit); printk(MODULE_NAME "CHH: %02x:%02x:%02x:%02x:%02x:%02x \n", eep_mac_addr[0],eep_mac_addr[1],eep_mac_addr[2], eep_mac_addr[3],eep_mac_addr[4],eep_mac_addr[5]); /* ** Check for a valid manufacturer prefix. If not, then use the defaults */ if(eep_mac_addr[0] == 0x00 && eep_mac_addr[1] == 0x03 && eep_mac_addr[2] == 0x7f) { memcpy(mac_addr, eep_mac_addr, 6); } else { /* Use Default address at top of range */ mac_addr[0] = 0x00; mac_addr[1] = 0x03; mac_addr[2] = 0x7F; mac_addr[3] = 0xFF; mac_addr[4] = 0xFF; mac_addr[5] = 0xFF - mac->mac_unit; }}static intag7100_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd){#ifndef CONFIG_ATHRS26_PHY printk(MODULE_NAME ": unsupported ioctl\n"); return -EOPNOTSUPP;#else return athr_ioctl(ifr->ifr_data, cmd);#endif}static struct net_device_stats *ag7100_get_stats(struct net_device *dev){ ag7100_mac_t *mac = dev->priv; struct Qdisc *sch; int i; sch = rcu_dereference(dev->qdisc); mac->mac_net_stats.tx_dropped = sch->qstats.drops; i = ag7100_get_rx_count(mac) - mac->net_rx_packets; if (i<0) i=0; mac->mac_net_stats.rx_missed_errors = i; return &mac->mac_net_stats;}static voidag7100_vet_tx_len_per_pkt(unsigned int *len){ unsigned int l; /* make it into words */ l = *len & ~3; /* * Not too small */ if (l < AG7100_TX_MIN_DS_LEN) l = AG7100_TX_MIN_DS_LEN; else /* Avoid len where we know we will deadlock, that * is the range between fif_len/2 and the MTU size */ if (l > AG7100_TX_FIFO_LEN/2) if (l < AG7100_TX_MTU_LEN) l = AG7100_TX_MTU_LEN; else if (l > AG7100_TX_MAX_DS_LEN) l = AG7100_TX_MAX_DS_LEN; *len = l;}/* * All allocations (except irq and rings). */static int __initag7100_init(void){ int i; struct net_device *dev; ag7100_mac_t *mac; uint32_t mask; /* * tx_len_per_ds is the number of bytes per data transfer in word increments. * * If the value is 0 than we default the value to a known good value based * on benchmarks. Otherwise we use the value specified - within some * cosntraints of course. * * Tested working values are 256, 512, 768, 1024 & 1536. * * A value of 256 worked best in all benchmarks. That is the default. * */ /* Tested 256, 512, 768, 1024, 1536 OK, 1152 and 1280 failed*/ if (0 == tx_len_per_ds) tx_len_per_ds = CONFIG_AG7100_LEN_PER_TX_DS; ag7100_vet_tx_len_per_pkt( &tx_len_per_ds); printk(MODULE_NAME ": Length per segment %d\n", tx_len_per_ds); /* * Compute the number of descriptors for an MTU */#ifndef CONFIG_AR9100 tx_max_desc_per_ds_pkt = AG7100_TX_MAX_DS_LEN / tx_len_per_ds; if (AG7100_TX_MAX_DS_LEN % tx_len_per_ds) tx_max_desc_per_ds_pkt++;#else tx_max_desc_per_ds_pkt =1;#endif printk(MODULE_NAME ": Max segments per packet %d\n", tx_max_desc_per_ds_pkt); printk(MODULE_NAME ": Max tx descriptor count %d\n", AG7100_TX_DESC_CNT); printk(MODULE_NAME ": Max rx descriptor count %d\n", AG7100_RX_DESC_CNT); /* * Let hydra know how much to put into the fifo in words (for tx) */ if (0 == fifo_3) fifo_3 = 0x000001ff | ((AG7100_TX_FIFO_LEN-tx_len_per_ds)/4)<<16; printk(MODULE_NAME ": fifo cfg 3 %08x\n", fifo_3); /* ** Do the rest of the initializations */ for(i = 0; i < AG7100_NMACS; i++) { mac = kmalloc(sizeof(ag7100_mac_t), GFP_KERNEL); if (!mac) { printk(MODULE_NAME ": unable to allocate mac\n"); return 1; } memset(mac, 0, sizeof(ag7100_mac_t)); mac->mac_unit = i; mac->mac_base = ag7100_mac_base(i); mac->mac_irq = ag7100_mac_irq(i); ag7100_macs[i] = mac; spin_lock_init(&mac->mac_lock); /* * out of memory timer */ init_timer(&mac->mac_oom_timer); mac->mac_oom_timer.data = (unsigned long)mac; mac->mac_oom_timer.function = ag7100_oom_timer; /* * watchdog task */ INIT_WORK(&mac->mac_tx_timeout, ag7100_tx_timeout_task, mac); dev = alloc_etherdev(0); if (!dev) { kfree(mac); printk("%s Freeing at 0x%lx\n",__func__,(unsigned long) mac); printk(MODULE_NAME ": unable to allocate etherdev\n"); return 1; } mac->mac_dev = dev; dev->get_stats = ag7100_get_stats; dev->open = ag7100_open; dev->stop = ag7100_stop; dev->hard_start_xmit = ag7100_hard_start;#ifdef CONFIG_ATHRS26_PHY dev->do_ioctl = ag7100_do_ioctl;#else dev->do_ioctl = NULL;#endif dev->poll = ag7100_poll; dev->weight = AG7100_NAPI_WEIGHT; dev->tx_timeout = ag7100_tx_timeout; dev->priv = mac; ag7100_get_default_macaddr(mac, dev->dev_addr); if (register_netdev(dev)) { printk(MODULE_NAME ": register netdev failed\n"); goto failed; } ag7100_reg_rmw_set(mac, AG7100_MAC_CFG1, AG7100_MAC_CFG1_SOFT_RST); udelay(20); mask = ag7100_reset_mask(mac->mac_unit); /* * put into reset, hold, pull out. */ ar7100_reg_rmw_set(AR7100_RESET, mask); mdelay(100); ar7100_reg_rmw_clear(AR7100_RESET, mask); mdelay(100); } ag7100_trc_init();#if defined(CONFIG_ATHRS26_PHY) athrs26_reg_dev(ag7100_macs);#endif return 0;failed: for(i = 0; i < AG7100_NMACS; i++) { if (!ag7100_macs[i]) continue; if (ag7100_macs[i]->mac_dev) free_netdev(ag7100_macs[i]->mac_dev); kfree(ag7100_macs[i]); printk("%s Freeing at 0x%lx\n",__func__,(unsigned long) ag7100_macs[i]); } return 1;}static void __exitag7100_cleanup(void){ int i; for(i = 0; i < AG7100_NMACS; i++) { unregister_netdev(ag7100_macs[i]->mac_dev); free_netdev(ag7100_macs[i]->mac_dev); kfree(ag7100_macs[i]); printk("%s Freeing at 0x%lx\n",__func__,(unsigned long) ag7100_macs[i]); } printk(MODULE_NAME ": cleanup done\n");}module_init(ag7100_init);module_exit(ag7100_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -