static int __devexit cpsw_remove(struct platform_device *pdev) { struct net_device *ndev = platform_get_drvdata(pdev); struct cpsw_priv *priv = netdev_priv(ndev); pr_info("removing device"); platform_set_drvdata(pdev, NULL); free_irq(ndev->irq, priv); cpsw_ale_destroy(priv->ale); cpdma_chan_destroy(priv->txch); cpdma_chan_destroy(priv->rxch); cpdma_ctlr_destroy(priv->dma); iounmap(priv->regs); release_mem_region(priv->cpsw_res->start, resource_size(priv->cpsw_res)); release_mem_region(priv->cpsw_ss_res->start, resource_size(priv->cpsw_ss_res)); clk_put(priv->clk); kfree(priv->slaves); free_netdev(ndev); return 0; }
int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr) { unsigned long flags; int ret = 0, i; if (!ctlr) return -EINVAL; spin_lock_irqsave(&ctlr->lock, flags); if (ctlr->state != CPDMA_STATE_IDLE) cpdma_ctlr_stop(ctlr); for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) cpdma_chan_destroy(ctlr->channels[i]); cpdma_desc_pool_destroy(ctlr->pool); spin_unlock_irqrestore(&ctlr->lock, flags); kfree(ctlr); return ret; }
int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr) { rtdm_lockctx_t context; int ret = 0, i; if (!ctlr) return -EINVAL; rtdm_lock_get_irqsave(&ctlr->lock, context); if (ctlr->state != CPDMA_STATE_IDLE) cpdma_ctlr_stop(ctlr); for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) { if (ctlr->channels[i]) cpdma_chan_destroy(ctlr->channels[i]); } cpdma_desc_pool_destroy(ctlr->pool); rtdm_lock_put_irqrestore(&ctlr->lock, context); kfree(ctlr); return ret; }
static int __devinit cpsw_probe(struct platform_device *pdev) { struct cpsw_platform_data *data = pdev->dev.platform_data; struct net_device *ndev; struct cpsw_priv *priv; struct cpdma_params dma_params; struct cpsw_ale_params ale_params; void __iomem *regs; struct resource *res; int ret = 0, i, k = 0; if (!data) { pr_err("platform data missing\n"); return -ENODEV; } ndev = alloc_etherdev(sizeof(struct cpsw_priv)); if (!ndev) { pr_err("error allocating net_device\n"); return -ENOMEM; } platform_set_drvdata(pdev, ndev); priv = netdev_priv(ndev); spin_lock_init(&priv->lock); priv->data = *data; priv->pdev = pdev; priv->ndev = ndev; priv->dev = &ndev->dev; priv->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG); priv->rx_packet_max = max(rx_packet_max, 128); if (is_valid_ether_addr(data->slave_data[0].mac_addr)) { memcpy(priv->mac_addr, data->slave_data[0].mac_addr, ETH_ALEN); pr_info("Detected MACID = %pM", priv->mac_addr); } else { random_ether_addr(priv->mac_addr); pr_info("Random MACID = %pM", priv->mac_addr); } memcpy(ndev->dev_addr, priv->mac_addr, ETH_ALEN); priv->slaves = kzalloc(sizeof(struct cpsw_slave) * data->slaves, GFP_KERNEL); if (!priv->slaves) { ret = -EBUSY; goto clean_ndev_ret; } for (i = 0; i < data->slaves; i++) priv->slaves[i].slave_num = i; priv->clk = clk_get(&pdev->dev, NULL); if (IS_ERR(priv->clk)) { dev_err(priv->dev, "failed to get device clock)\n"); ret = -EBUSY; } priv->cpsw_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!priv->cpsw_res) { dev_err(priv->dev, "error getting i/o resource\n"); ret = -ENOENT; goto clean_clk_ret; } if (!request_mem_region(priv->cpsw_res->start, resource_size(priv->cpsw_res), ndev->name)) { dev_err(priv->dev, "failed request i/o region\n"); ret = -ENXIO; goto clean_clk_ret; } regs = ioremap(priv->cpsw_res->start, resource_size(priv->cpsw_res)); if (!regs) { dev_err(priv->dev, "unable to map i/o region\n"); goto clean_cpsw_iores_ret; } priv->regs = regs; priv->host_port = data->host_port_num; priv->host_port_regs = regs + data->host_port_reg_ofs; priv->cpsw_ss_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); if (!priv->cpsw_ss_res) { dev_err(priv->dev, "error getting i/o resource\n"); ret = -ENOENT; goto clean_clk_ret; } if (!request_mem_region(priv->cpsw_ss_res->start, resource_size(priv->cpsw_ss_res), ndev->name)) { dev_err(priv->dev, "failed request i/o region\n"); ret = -ENXIO; goto clean_clk_ret; } regs = ioremap(priv->cpsw_ss_res->start, resource_size(priv->cpsw_ss_res)); if (!regs) { dev_err(priv->dev, "unable to map i/o region\n"); goto clean_cpsw_ss_iores_ret; } priv->ss_regs = regs; for_each_slave(priv, cpsw_slave_init, priv); memset(&dma_params, 0, sizeof(dma_params)); dma_params.dev = &pdev->dev; dma_params.dmaregs = cpsw_dma_regs((u32)priv->regs, data->cpdma_reg_ofs); dma_params.rxthresh = cpsw_dma_rxthresh((u32)priv->regs, data->cpdma_reg_ofs); dma_params.rxfree = cpsw_dma_rxfree((u32)priv->regs, data->cpdma_reg_ofs); dma_params.txhdp = cpsw_dma_txhdp((u32)priv->regs, data->cpdma_sram_ofs); dma_params.rxhdp = cpsw_dma_rxhdp((u32)priv->regs, data->cpdma_sram_ofs); dma_params.txcp = cpsw_dma_txcp((u32)priv->regs, data->cpdma_sram_ofs); dma_params.rxcp = cpsw_dma_rxcp((u32)priv->regs, data->cpdma_sram_ofs); dma_params.num_chan = data->channels; dma_params.has_soft_reset = true; dma_params.min_packet_size = CPSW_MIN_PACKET_SIZE; dma_params.desc_mem_size = data->bd_ram_size; dma_params.desc_align = 16; dma_params.has_ext_regs = true; dma_params.desc_mem_phys = data->no_bd_ram ? 0 : (u32 __force)priv->cpsw_res->start + data->bd_ram_ofs; dma_params.desc_hw_addr = data->hw_ram_addr ? data->hw_ram_addr : dma_params.desc_mem_phys ; priv->dma = cpdma_ctlr_create(&dma_params); if (!priv->dma) { dev_err(priv->dev, "error initializing dma\n"); ret = -ENOMEM; goto clean_iomap_ret; } priv->txch = cpdma_chan_create(priv->dma, tx_chan_num(0), cpsw_tx_handler); priv->rxch = cpdma_chan_create(priv->dma, rx_chan_num(0), cpsw_rx_handler); if (WARN_ON(!priv->txch || !priv->rxch)) { dev_err(priv->dev, "error initializing dma channels\n"); ret = -ENOMEM; goto clean_dma_ret; } memset(&ale_params, 0, sizeof(ale_params)); ale_params.dev = &ndev->dev; ale_params.ale_regs = (void *)((u32)priv->regs) + ((u32)data->ale_reg_ofs); ale_params.ale_ageout = ale_ageout; ale_params.ale_entries = data->ale_entries; ale_params.ale_ports = data->slaves; priv->ale = cpsw_ale_create(&ale_params); if (!priv->ale) { dev_err(priv->dev, "error initializing ale engine\n"); ret = -ENODEV; goto clean_dma_ret; } ndev->irq = platform_get_irq(pdev, 0); if (ndev->irq < 0) { dev_err(priv->dev, "error getting irq resource\n"); ret = -ENOENT; goto clean_ale_ret; } while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) { for (i = res->start; i <= res->end; i++) { if (request_irq(i, cpsw_interrupt, IRQF_DISABLED, dev_name(&pdev->dev), priv)) { dev_err(priv->dev, "error attaching irq\n"); goto clean_ale_ret; } priv->irqs_table[k] = i; priv->num_irqs = k; } k++; } ndev->flags |= IFF_ALLMULTI; /* */ ndev->netdev_ops = &cpsw_netdev_ops; SET_ETHTOOL_OPS(ndev, &cpsw_ethtool_ops); netif_napi_add(ndev, &priv->napi, cpsw_poll, CPSW_POLL_WEIGHT); /* */ SET_NETDEV_DEV(ndev, &pdev->dev); ret = register_netdev(ndev); if (ret) { dev_err(priv->dev, "error registering net device\n"); ret = -ENODEV; goto clean_irq_ret; } cpsw_notice(priv, probe, "initialized device (regs %x, irq %d)\n", priv->cpsw_res->start, ndev->irq); return 0; clean_irq_ret: free_irq(ndev->irq, priv); clean_ale_ret: cpsw_ale_destroy(priv->ale); clean_dma_ret: cpdma_chan_destroy(priv->txch); cpdma_chan_destroy(priv->rxch); cpdma_ctlr_destroy(priv->dma); clean_iomap_ret: iounmap(priv->regs); clean_cpsw_ss_iores_ret: release_mem_region(priv->cpsw_ss_res->start, resource_size(priv->cpsw_ss_res)); clean_cpsw_iores_ret: release_mem_region(priv->cpsw_res->start, resource_size(priv->cpsw_res)); clean_clk_ret: clk_put(priv->clk); kfree(priv->slaves); clean_ndev_ret: free_netdev(ndev); return ret; }