diff options
Diffstat (limited to 'drivers/net/ucc_geth.c')
-rw-r--r-- | drivers/net/ucc_geth.c | 95 |
1 files changed, 81 insertions, 14 deletions
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index abac7db3819..fba0811d260 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -2084,8 +2084,10 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth) if (!ugeth) return; - if (ugeth->uccf) + if (ugeth->uccf) { ucc_fast_free(ugeth->uccf); + ugeth->uccf = NULL; + } if (ugeth->p_thread_data_tx) { qe_muram_free(ugeth->thread_dat_tx_offset); @@ -2305,10 +2307,6 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth) ug_info = ugeth->ug_info; uf_info = &ug_info->uf_info; - /* Create CQs for hash tables */ - INIT_LIST_HEAD(&ugeth->group_hash_q); - INIT_LIST_HEAD(&ugeth->ind_hash_q); - if (!((uf_info->bd_mem_part == MEM_PART_SYSTEM) || (uf_info->bd_mem_part == MEM_PART_MURAM))) { if (netif_msg_probe(ugeth)) @@ -3614,9 +3612,6 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) ugeth_vdbg("%s: IN", __FUNCTION__); - if (!ugeth) - return IRQ_NONE; - uccf = ugeth->uccf; ug_info = ugeth->ug_info; @@ -3671,6 +3666,23 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) return IRQ_HANDLED; } +#ifdef CONFIG_NET_POLL_CONTROLLER +/* + * Polling 'interrupt' - used by things like netconsole to send skbs + * without having to re-enable interrupts. It's not called while + * the interrupt routine is executing. + */ +static void ucc_netpoll(struct net_device *dev) +{ + struct ucc_geth_private *ugeth = netdev_priv(dev); + int irq = ugeth->ug_info->uf_info.irq; + + disable_irq(irq); + ucc_geth_irq_handler(irq, dev); + enable_irq(irq); +} +#endif /* CONFIG_NET_POLL_CONTROLLER */ + /* Called when something needs to use the ethernet device */ /* Returns 0 for success. */ static int ucc_geth_open(struct net_device *dev) @@ -3822,6 +3834,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma int err, ucc_num, max_speed = 0; const phandle *ph; const unsigned int *prop; + const char *sprop; const void *mac_addr; phy_interface_t phy_interface; static const int enet_to_speed[] = { @@ -3854,10 +3867,56 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma ug_info->uf_info.ucc_num = ucc_num; - prop = of_get_property(np, "rx-clock", NULL); - ug_info->uf_info.rx_clock = *prop; - prop = of_get_property(np, "tx-clock", NULL); - ug_info->uf_info.tx_clock = *prop; + sprop = of_get_property(np, "rx-clock-name", NULL); + if (sprop) { + ug_info->uf_info.rx_clock = qe_clock_source(sprop); + if ((ug_info->uf_info.rx_clock < QE_CLK_NONE) || + (ug_info->uf_info.rx_clock > QE_CLK24)) { + printk(KERN_ERR + "ucc_geth: invalid rx-clock-name property\n"); + return -EINVAL; + } + } else { + prop = of_get_property(np, "rx-clock", NULL); + if (!prop) { + /* If both rx-clock-name and rx-clock are missing, + we want to tell people to use rx-clock-name. */ + printk(KERN_ERR + "ucc_geth: missing rx-clock-name property\n"); + return -EINVAL; + } + if ((*prop < QE_CLK_NONE) || (*prop > QE_CLK24)) { + printk(KERN_ERR + "ucc_geth: invalid rx-clock propperty\n"); + return -EINVAL; + } + ug_info->uf_info.rx_clock = *prop; + } + + sprop = of_get_property(np, "tx-clock-name", NULL); + if (sprop) { + ug_info->uf_info.tx_clock = qe_clock_source(sprop); + if ((ug_info->uf_info.tx_clock < QE_CLK_NONE) || + (ug_info->uf_info.tx_clock > QE_CLK24)) { + printk(KERN_ERR + "ucc_geth: invalid tx-clock-name property\n"); + return -EINVAL; + } + } else { + prop = of_get_property(np, "rx-clock", NULL); + if (!prop) { + printk(KERN_ERR + "ucc_geth: mising tx-clock-name property\n"); + return -EINVAL; + } + if ((*prop < QE_CLK_NONE) || (*prop > QE_CLK24)) { + printk(KERN_ERR + "ucc_geth: invalid tx-clock property\n"); + return -EINVAL; + } + ug_info->uf_info.tx_clock = *prop; + } + err = of_address_to_resource(np, 0, &res); if (err) return -EINVAL; @@ -3946,6 +4005,10 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma ugeth = netdev_priv(dev); spin_lock_init(&ugeth->lock); + /* Create CQs for hash tables */ + INIT_LIST_HEAD(&ugeth->group_hash_q); + INIT_LIST_HEAD(&ugeth->ind_hash_q); + dev_set_drvdata(device, dev); /* Set the dev->base_addr to the gfar reg region */ @@ -3962,6 +4025,9 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma #ifdef CONFIG_UGETH_NAPI netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, UCC_GETH_DEV_WEIGHT); #endif /* CONFIG_UGETH_NAPI */ +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ucc_netpoll; +#endif dev->stop = ucc_geth_close; // dev->change_mtu = ucc_geth_change_mtu; dev->mtu = 1500; @@ -3996,9 +4062,10 @@ static int ucc_geth_remove(struct of_device* ofdev) struct net_device *dev = dev_get_drvdata(device); struct ucc_geth_private *ugeth = netdev_priv(dev); - dev_set_drvdata(device, NULL); - ucc_geth_memclean(ugeth); + unregister_netdev(dev); free_netdev(dev); + ucc_geth_memclean(ugeth); + dev_set_drvdata(device, NULL); return 0; } |