diff options
| author | juhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2007-10-16 13:12:51 +0000 | 
|---|---|---|
| committer | juhosg <juhosg@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2007-10-16 13:12:51 +0000 | 
| commit | bf123d56d43e31c09b86faa9d8eee82475e5dab5 (patch) | |
| tree | 29940b24559550a4bc5d7cf570585eb06a6a22c6 | |
| parent | c5f3f8343e9773bdf56cbbf8651b0db1d6e48c28 (diff) | |
[adm5120] switch driver cleanup, 3rd phase
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@9334 3c298f89-4303-0410-b956-a3cf2f4a3e73
| -rw-r--r-- | target/linux/adm5120/files/drivers/net/adm5120sw.c | 374 | 
1 files changed, 214 insertions, 160 deletions
diff --git a/target/linux/adm5120/files/drivers/net/adm5120sw.c b/target/linux/adm5120/files/drivers/net/adm5120sw.c index 987e1de31..e354a35a6 100644 --- a/target/linux/adm5120/files/drivers/net/adm5120sw.c +++ b/target/linux/adm5120/files/drivers/net/adm5120sw.c @@ -163,7 +163,6 @@ static spinlock_t sw_lock = SPIN_LOCK_UNLOCKED;  static spinlock_t poll_lock = SPIN_LOCK_UNLOCKED;  static struct net_device sw_dev; -static struct net_device *poll_dev;  /* ------------------------------------------------------------------------ */ @@ -458,31 +457,6 @@ static int adm5120_switch_rx(int limit)  } -static int adm5120_switch_poll(struct net_device *dev, int *budget) -{ -	int limit = min(dev->quota, *budget); -	int done; -	u32 status; - -	done = adm5120_switch_rx(limit); - -	*budget -= done; -	dev->quota -= done; - -	status = sw_int_status() & SWITCH_INTS_POLL; -	if ((done < limit) && (!status)) { -		spin_lock_irq(&poll_lock); -		SW_DBG("disable polling mode for %s\n", poll_dev->name); -		netif_rx_complete(poll_dev); -		sw_int_unmask(SWITCH_INTS_POLL); -		poll_dev = NULL; -		spin_unlock_irq(&poll_lock); -		return 0; -	} - -	return 1; -} -  static void adm5120_switch_tx(void)  {  	unsigned int entry; @@ -517,6 +491,28 @@ static void adm5120_switch_tx(void)  	}  } +static int adm5120_if_poll(struct net_device *dev, int *budget) +{ +	int limit = min(dev->quota, *budget); +	int done; +	u32 status; + +	done = adm5120_switch_rx(limit); + +	*budget -= done; +	dev->quota -= done; + +	status = sw_int_status() & SWITCH_INTS_POLL; +	if ((done < limit) && (!status)) { +		SW_DBG("disable polling mode for %s\n", poll_dev->name); +		netif_rx_complete(dev); +		sw_int_unmask(SWITCH_INTS_POLL); +		return 0; +	} + +	return 1; +} +  static irqreturn_t adm5120_poll_irq(int irq, void *dev_id)  {  	struct net_device *dev = dev_id; @@ -529,19 +525,9 @@ static irqreturn_t adm5120_poll_irq(int irq, void *dev_id)  	sw_dump_intr_mask("poll ints", status); -	if (!netif_running(dev)) { -		SW_DBG("device %s is not running\n", dev->name); -		return IRQ_NONE; -	} - -	spin_lock(&poll_lock); -	if (!poll_dev) { -		SW_DBG("enable polling mode for %s\n", dev->name); -		poll_dev = dev; -		sw_int_mask(SWITCH_INTS_POLL); -		netif_rx_schedule(poll_dev); -	} -	spin_unlock(&poll_lock); +	SW_DBG("enable polling mode for %s\n", dev->name); +	sw_int_mask(SWITCH_INTS_POLL); +	netif_rx_schedule(dev);  	return IRQ_HANDLED;  } @@ -605,12 +591,143 @@ static void adm5120_set_bw(char *matrix)  		sw_read_reg(SWITCH_REG_BW_CNTL1));  } -static int adm5120_switch_open(struct net_device *dev) +static void adm5120_switch_tx_ring_reset(struct dma_desc *desc, +		struct sk_buff **skbl, int num) +{ +	memset(desc, 0, num * sizeof(*desc)); +	desc[num-1].buf1 |= DESC_EOR; +	memset(skbl, 0, sizeof(struct skb*)*num); + +	cur_txl = 0; +	dirty_txl = 0; +} + +static void adm5120_switch_rx_ring_reset(struct dma_desc *desc, +		struct sk_buff **skbl, int num) +{ +	int i; + +	memset(desc, 0, num * sizeof(*desc)); +	for (i = 0; i < num; i++) { +		skbl[i] = dev_alloc_skb(SKB_ALLOC_LEN); +		if (!skbl[i]) { +			i = num; +			break; +		} +		skb_reserve(skbl[i], SKB_RESERVE_LEN); +		adm5120_rx_dma_update(&desc[i], skbl[i], (num-1==i)); +	} + +	cur_rxl = 0; +	dirty_rxl = 0; +} + +static int adm5120_switch_tx_ring_alloc(void) +{ +	int err; + +	txl_descs = dma_alloc_coherent(NULL, TX_DESCS_SIZE, &txl_descs_dma, +					GFP_ATOMIC); +	if (!txl_descs) { +		err = -ENOMEM; +		goto err; +	} + +	txl_skbuff = kzalloc(TX_SKBS_SIZE, GFP_KERNEL); +	if (!txl_skbuff) { +		err = -ENOMEM; +		goto err; +	} + +	return 0; + +err: +	return err; +} + +static void adm5120_switch_tx_ring_free(void) +{ +	int i; + +	if (txl_skbuff) { +		for (i = 0; i < TX_RING_SIZE; i++) +			if (txl_skbuff[i]) +				kfree_skb(txl_skbuff[i]); +		kfree(txl_skbuff); +	} + +	if (txl_descs) +		dma_free_coherent(NULL, TX_DESCS_SIZE, txl_descs, +			txl_descs_dma); +} + +static int adm5120_switch_rx_ring_alloc(void) +{ +	int err; +	int i; + +	/* init RX ring */ +	rxl_descs = dma_alloc_coherent(NULL, RX_DESCS_SIZE, &rxl_descs_dma, +					GFP_ATOMIC); +	if (!rxl_descs) { +		err = -ENOMEM; +		goto err; +	} + +	rxl_skbuff = kzalloc(RX_SKBS_SIZE, GFP_KERNEL); +	if (!rxl_skbuff) { +		err = -ENOMEM; +		goto err; +	} + +	for (i = 0; i < RX_RING_SIZE; i++) { +		struct sk_buff *skb; +		skb = alloc_skb(SKB_ALLOC_LEN, GFP_ATOMIC); +		if (!skb) { +			err = -ENOMEM; +			goto err; +		} +		rxl_skbuff[i] = skb; +		skb_reserve(skb, SKB_RESERVE_LEN); +	} + +	return 0; + +err: +	return err; +} + +static void adm5120_switch_rx_ring_free(void) +{ +	int i; + +	if (rxl_skbuff) { +		for (i = 0; i < RX_RING_SIZE; i++) +			if (rxl_skbuff[i]) +				kfree_skb(rxl_skbuff[i]); +		kfree(rxl_skbuff); +	} + +	if (rxl_descs) +		dma_free_coherent(NULL, RX_DESCS_SIZE, rxl_descs, +			rxl_descs_dma); +} + +/* ------------------------------------------------------------------------ */ + +static int adm5120_if_open(struct net_device *dev)  {  	u32 t; +	int err;  	int i; -	netif_start_queue(dev); +	err = request_irq(dev->irq, adm5120_poll_irq, +		(IRQF_SHARED | IRQF_DISABLED), dev->name, dev); +	if (err) { +		SW_ERR("unable to get irq for %s\n", dev->name); +		goto err; +	} +  	if (!sw_used++)  		/* enable interrupts on first open */  		sw_int_unmask(SWITCH_INTS_USED); @@ -623,16 +740,20 @@ static int adm5120_switch_open(struct net_device *dev)  	}  	sw_write_reg(SWITCH_REG_PORT_CONF0, t); +	netif_start_queue(dev); +  	return 0; + +err: +	return err;  } -static int adm5120_switch_stop(struct net_device *dev) +static int adm5120_if_stop(struct net_device *dev)  {  	u32 t;  	int i; -	if (!--sw_used) -		sw_int_mask(SWITCH_INTS_USED); +	netif_stop_queue(dev);  	/* disable port if not assigned to other devices */  	t = sw_read_reg(SWITCH_REG_PORT_CONF0); @@ -643,11 +764,16 @@ static int adm5120_switch_stop(struct net_device *dev)  	}  	sw_write_reg(SWITCH_REG_PORT_CONF0, t); -	netif_stop_queue(dev); +	if (!--sw_used) +		sw_int_mask(SWITCH_INTS_USED); + +	free_irq(dev->irq, dev); +  	return 0;  } -static int adm5120_sw_start_xmit(struct sk_buff *skb, struct net_device *dev) +static int adm5120_if_hard_start_xmit(struct sk_buff *skb, +		struct net_device *dev)  {  	struct dma_desc *desc;  	struct adm5120_sw *priv = netdev_priv(dev); @@ -695,7 +821,7 @@ static int adm5120_sw_start_xmit(struct sk_buff *skb, struct net_device *dev)  	return 0;  } -static void adm5120_tx_timeout(struct net_device *dev) +static void adm5120_if_tx_timeout(struct net_device *dev)  {  	SW_INFO("TX timeout on %s\n",dev->name);  } @@ -769,7 +895,7 @@ static void adm5120_write_mac(struct net_device *dev)  	while (!(sw_read_reg(SWITCH_REG_MAC_WT0) & MAC_WT0_MWD));  } -static int adm5120_sw_set_mac_address(struct net_device *dev, void *p) +static int adm5120_if_set_mac_address(struct net_device *dev, void *p)  {  	struct sockaddr *addr = p; @@ -778,7 +904,7 @@ static int adm5120_sw_set_mac_address(struct net_device *dev, void *p)  	return 0;  } -static int adm5120_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +static int adm5120_if_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)  {  	int err;  	struct adm5120_sw_info info; @@ -827,29 +953,30 @@ static int adm5120_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)  	return 0;  } -static void adm5120_dma_tx_init(struct dma_desc *desc, struct sk_buff **skbl, -		int num) +static struct net_device *adm5120_if_alloc(void)  { -	memset(desc, 0, num * sizeof(*desc)); -	desc[num-1].buf1 |= DESC_EOR; -	memset(skbl, 0, sizeof(struct skb*)*num); -} - -static void adm5120_dma_rx_init(struct dma_desc *desc, struct sk_buff **skbl, -		int num) -{ -	int i; - -	memset(desc, 0, num * sizeof(*desc)); -	for (i=0; i<num; i++) { -		skbl[i] = dev_alloc_skb(SKB_ALLOC_LEN); -		if (!skbl[i]) { -			i=num; -			break; -		} -		skb_reserve(skbl[i], SKB_RESERVE_LEN); -		adm5120_rx_dma_update(&desc[i], skbl[i], (num-1==i)); -	} +	struct net_device *dev; +	struct adm5120_sw *priv; + +	dev = alloc_etherdev(sizeof(*priv)); +	if (!dev) +		return NULL; + +	dev->irq		= ADM5120_IRQ_SWITCH; +	dev->open		= adm5120_if_open; +	dev->hard_start_xmit 	= adm5120_if_hard_start_xmit; +	dev->stop		= adm5120_if_stop; +	dev->set_multicast_list	= adm5120_set_multicast_list; +	dev->do_ioctl		= adm5120_if_do_ioctl; +	dev->tx_timeout		= adm5120_if_tx_timeout; +	dev->watchdog_timeo 	= TX_TIMEOUT; +	dev->set_mac_address 	= adm5120_if_set_mac_address; +	dev->poll		= adm5120_if_poll; +	dev->weight		= 64; + +	SET_MODULE_OWNER(dev); + +	return dev;  }  static void adm5120_switch_cleanup(void) @@ -863,41 +990,18 @@ static void adm5120_switch_cleanup(void)  		struct net_device *dev = adm5120_devs[i];  		if (dev) {  			unregister_netdev(dev); -			free_irq(ADM5120_IRQ_SWITCH, dev);  			free_netdev(dev);  		}  	} -	/* cleanup TX ring */ -	if (txl_skbuff) { -		for (i = 0; i < TX_RING_SIZE; i++) -			if (txl_skbuff[i]) -				kfree_skb(txl_skbuff[i]); -		kfree(txl_skbuff); -	} - -	if (txl_descs) -		dma_free_coherent(NULL, TX_DESCS_SIZE, txl_descs, -			txl_descs_dma); - -	/* cleanup RX ring */ -	if (rxl_skbuff) { -		for (i = 0; i < RX_RING_SIZE; i++) -			if (rxl_skbuff[i]) -				kfree_skb(rxl_skbuff[i]); -		kfree(rxl_skbuff); -	} - -	if (rxl_descs) -		dma_free_coherent(NULL, RX_DESCS_SIZE, rxl_descs, -			rxl_descs_dma); +	adm5120_switch_tx_ring_free(); +	adm5120_switch_rx_ring_free();  	free_irq(ADM5120_IRQ_SWITCH, &sw_dev);  }  static int __init adm5120_switch_init(void)  { -	struct net_device *dev;  	u32 t;  	int i, err; @@ -939,49 +1043,16 @@ static int __init adm5120_switch_init(void)  	sw_int_mask(SWITCH_INTS_ALL);  	sw_int_ack(SWITCH_INTS_ALL); -	/* init RX ring */ -	cur_rxl = dirty_rxl = 0; -	rxl_descs = dma_alloc_coherent(NULL, RX_DESCS_SIZE, &rxl_descs_dma, -					GFP_ATOMIC); -	if (!rxl_descs) { -		err = -ENOMEM; -		goto err; -	} - -	rxl_skbuff = kzalloc(RX_SKBS_SIZE, GFP_KERNEL); -	if (!rxl_skbuff) { -		err = -ENOMEM; +	err = adm5120_switch_rx_ring_alloc(); +	if (err)  		goto err; -	} - -	for (i = 0; i < RX_RING_SIZE; i++) { -		struct sk_buff *skb; -		skb = alloc_skb(SKB_ALLOC_LEN, GFP_ATOMIC); -		if (!skb) { -			err = -ENOMEM; -			goto err; -		} -		rxl_skbuff[i] = skb; -		skb_reserve(skb, SKB_RESERVE_LEN); -	} -	/* init TX ring */ -	cur_txl = dirty_txl = 0; -	txl_descs = dma_alloc_coherent(NULL, TX_DESCS_SIZE, &txl_descs_dma, -					GFP_ATOMIC); -	if (!txl_descs) { -		err = -ENOMEM; +	err = adm5120_switch_tx_ring_alloc(); +	if (err)  		goto err; -	} -	txl_skbuff = kzalloc(TX_SKBS_SIZE, GFP_KERNEL); -	if (!txl_skbuff) { -		err = -ENOMEM; -		goto err; -	} - -	adm5120_dma_tx_init(txl_descs, txl_skbuff, TX_RING_SIZE); -	adm5120_dma_rx_init(rxl_descs, rxl_skbuff, RX_RING_SIZE); +	adm5120_switch_tx_ring_reset(txl_descs, txl_skbuff, TX_RING_SIZE); +	adm5120_switch_rx_ring_reset(rxl_descs, rxl_skbuff, RX_RING_SIZE);  	sw_write_reg(SWITCH_REG_SHDA, 0);  	sw_write_reg(SWITCH_REG_SLDA, KSEG1ADDR(txl_descs)); @@ -989,35 +1060,19 @@ static int __init adm5120_switch_init(void)  	sw_write_reg(SWITCH_REG_RLDA, KSEG1ADDR(rxl_descs));  	for (i = 0; i < SWITCH_NUM_PORTS; i++) { -		adm5120_devs[i] = alloc_etherdev(sizeof(struct adm5120_sw)); -		if (!adm5120_devs[i]) { +		struct net_device *dev; +		struct adm5120_sw *priv; + +		dev = adm5120_if_alloc(); +		if (!dev) {  			err = -ENOMEM;  			goto err;  		} -		dev = adm5120_devs[i]; -		err = request_irq(ADM5120_IRQ_SWITCH, adm5120_poll_irq, -			(IRQF_SHARED | IRQF_DISABLED), dev->name, dev); -		if (err) { -			SW_ERR("unable to get irq for %s\n", dev->name); -			goto err; -		} +		adm5120_devs[i] = dev; +		priv = netdev_priv(dev); -		SET_MODULE_OWNER(dev); -		memset(netdev_priv(dev), 0, sizeof(struct adm5120_sw)); -		((struct adm5120_sw*)netdev_priv(dev))->port = i; -		dev->base_addr = ADM5120_SWITCH_BASE; -		dev->irq = ADM5120_IRQ_SWITCH; -		dev->open = adm5120_switch_open; -		dev->hard_start_xmit = adm5120_sw_start_xmit; -		dev->stop = adm5120_switch_stop; -		dev->set_multicast_list = adm5120_set_multicast_list; -		dev->do_ioctl = adm5120_do_ioctl; -		dev->tx_timeout = adm5120_tx_timeout; -		dev->watchdog_timeo = TX_TIMEOUT; -		dev->set_mac_address = adm5120_sw_set_mac_address; -		dev->poll = adm5120_switch_poll; -		dev->weight = 64; +		priv->port = i;  		memcpy(dev->dev_addr, adm5120_eth_macs[i], 6);  		adm5120_write_mac(dev); @@ -1028,7 +1083,6 @@ static int __init adm5120_switch_init(void)  					dev->name, err);  			goto err;  		} -		SW_INFO("%s created for switch port%d\n", dev->name, i);  	}  	/* setup vlan/port mapping after devs are filled up */  | 
