diff options
| -rw-r--r-- | target/linux/package/switch/src/switch-adm.c | 58 | ||||
| -rw-r--r-- | target/linux/package/switch/src/switch-core.c | 98 | ||||
| -rw-r--r-- | target/linux/package/switch/src/switch-core.h | 12 | ||||
| -rw-r--r-- | target/linux/package/switch/src/switch-robo.c | 66 | 
4 files changed, 128 insertions, 106 deletions
| diff --git a/target/linux/package/switch/src/switch-adm.c b/target/linux/package/switch/src/switch-adm.c index 0b70a694c..6ad98447b 100644 --- a/target/linux/package/switch/src/switch-adm.c +++ b/target/linux/package/switch/src/switch-adm.c @@ -240,7 +240,7 @@ static int port_conf[] = { 0x01, 0x03, 0x05, 0x07, 0x08, 0x09 };  /* Bits in VLAN port mapping */  static int vlan_ports[] = { 1 << 0, 1 << 2, 1 << 4, 1 << 6, 1 << 7, 1 << 8 }; -static int handle_vlan_port_read(char *buf, int nr) +static int handle_vlan_port_read(void *driver, char *buf, int nr)  {  	int ports, i, c, len = 0; @@ -261,30 +261,33 @@ static int handle_vlan_port_read(char *buf, int nr)  	return len;  } -static int handle_vlan_port_write(char *buf, int nr) +static int handle_vlan_port_write(void *driver, char *buf, int nr)  { -	int i, c, ports; -	int map = switch_parse_vlan(buf); +	int i, cfg, ports; +	switch_driver *d = (switch_driver *) driver; +	switch_vlan_config *c = switch_parse_vlan(d, buf); -	if (map == -1) +	if (c == NULL)  		return -1;  	ports = adm_rreg(0, 0x13 + nr); -	for (i = 0; i <= 5; i++) { -		if (map & (1 << i)) { +	for (i = 0; i < d->ports; i++) { +		if (c->port & (1 << i)) {  			ports |= vlan_ports[i]; -			c = adm_rreg(0, port_conf[i]); +			cfg = adm_rreg(0, port_conf[i]);  			/* Tagging */ -			if (map & (1 << (8 + i))) -				c |= (1 << 4); +			if (c->untag & (1 << i)) +				cfg &= ~(1 << 4);  			else -				c &= ~(1 << 4); - -			c = (c & ~(0xf << 10)) | (nr << 10); +				cfg |= (1 << 4); -			adm_wreg(port_conf[i], (__u16) c); +			if ((c->untag | c->pvid) & (1 << i)) { +				cfg = (cfg & ~(0xf << 10)) | (nr << 10); +			} +			 +			adm_wreg(port_conf[i], (__u16) cfg);  		} else {  			ports &= ~(vlan_ports[i]);  		} @@ -294,12 +297,12 @@ static int handle_vlan_port_write(char *buf, int nr)  	return 0;  } -static int handle_port_enable_read(char *buf, int nr) +static int handle_port_enable_read(void *driver, char *buf, int nr)  {  	return sprintf(buf, "%d\n", ((adm_rreg(0, port_conf[nr]) & (1 << 5)) ? 0 : 1));  } -static int handle_port_enable_write(char *buf, int nr) +static int handle_port_enable_write(void *driver, char *buf, int nr)  {  	int reg = adm_rreg(0, port_conf[nr]); @@ -313,7 +316,7 @@ static int handle_port_enable_write(char *buf, int nr)  	return 0;  } -static int handle_port_media_read(char *buf, int nr) +static int handle_port_media_read(void *driver, char *buf, int nr)  {  	int len;  	int media = 0; @@ -330,7 +333,7 @@ static int handle_port_media_read(char *buf, int nr)  	return len + sprintf(buf + len, "\n");  } -static int handle_port_media_write(char *buf, int nr) +static int handle_port_media_write(void *driver, char *buf, int nr)  {  	int media = switch_parse_media(buf);  	int reg = adm_rreg(0, port_conf[nr]); @@ -351,12 +354,12 @@ static int handle_port_media_write(char *buf, int nr)  	return 0;  } -static int handle_vlan_enable_read(char *buf, int nr) +static int handle_vlan_enable_read(void *driver, char *buf, int nr)  {  	return sprintf(buf, "%d\n", ((adm_rreg(0, 0x11) & (1 << 5)) ? 1 : 0));  } -static int handle_vlan_enable_write(char *buf, int nr) +static int handle_vlan_enable_write(void *driver, char *buf, int nr)  {  	int reg = adm_rreg(0, 0x11); @@ -370,7 +373,7 @@ static int handle_vlan_enable_write(char *buf, int nr)  	return 0;  } -static int handle_reset(char *buf, int nr) +static int handle_reset(void *driver, char *buf, int nr)  {  	int i; @@ -412,7 +415,7 @@ static int handle_reset(char *buf, int nr)  	return 0;  } -static int handle_registers(char *buf, int nr) +static int handle_registers(void *driver, char *buf, int nr)  {  	int i, len = 0; @@ -423,7 +426,7 @@ static int handle_registers(char *buf, int nr)  	return len;  } -static int handle_counters(char *buf, int nr) +static int handle_counters(void *driver, char *buf, int nr)  {  	int i, len = 0; @@ -451,6 +454,13 @@ static int detect_adm()  #else  	ret = 1;  #endif +	if (ret == 1) { +		int i = adm_rreg(0, 0); +		if ((i == 0) || (i == 0xffff)) { +			printk("No ADM6996 chip detected.\n"); +			ret = 0; +		} +	}  	return ret;  } @@ -475,7 +485,9 @@ static int __init adm_init()  	};  	switch_driver driver = {  		name: DRIVER_NAME, +		interface: "eth0",  		ports: 6, +		cpuport: 5,  		vlans: 16,  		driver_handlers: cfg,  		port_handlers: port, diff --git a/target/linux/package/switch/src/switch-core.c b/target/linux/package/switch/src/switch-core.c index 8b4419b29..c0e5cc9ea 100644 --- a/target/linux/package/switch/src/switch-core.c +++ b/target/linux/package/switch/src/switch-core.c @@ -37,6 +37,7 @@ typedef struct {  	struct list_head list;  	struct proc_dir_entry *parent;  	int nr; +	void *driver;  	switch_config handler;  } switch_proc_handler; @@ -47,7 +48,6 @@ typedef struct {  	int nr;  } switch_priv; -  static ssize_t switch_proc_read(struct file *file, char *buf, size_t count, loff_t *ppos);  static ssize_t switch_proc_write(struct file *file, const char *buf, size_t count, void *data); @@ -56,7 +56,7 @@ static struct file_operations switch_proc_fops = {  	write: switch_proc_write  }; -static char *strdup(char *str) +static inline char *strdup(char *str)  {  	char *new = kmalloc(strlen(str) + 1, GFP_KERNEL);  	strcpy(new, str); @@ -80,7 +80,7 @@ static ssize_t switch_proc_read(struct file *file, char *buf, size_t count, loff  	if (dent->data != NULL) {  		switch_proc_handler *handler = (switch_proc_handler *) dent->data;  		if (handler->handler.read != NULL) -			len += handler->handler.read(page + len, handler->nr); +			len += handler->handler.read(handler->driver, page + len, handler->nr);  	}  	len += 1; @@ -122,7 +122,7 @@ static ssize_t switch_proc_write(struct file *file, const char *buf, size_t coun  	if (dent->data != NULL) {  		switch_proc_handler *handler = (switch_proc_handler *) dent->data;  		if (handler->handler.write != NULL) { -			if ((ret = handler->handler.write(page, handler->nr)) >= 0) +			if ((ret = handler->handler.write(handler->driver, page, handler->nr)) >= 0)  				ret = count;  		}  	} @@ -131,8 +131,9 @@ static ssize_t switch_proc_write(struct file *file, const char *buf, size_t coun  	return ret;  } -static void add_handlers(switch_priv *priv, switch_config *handlers, struct proc_dir_entry *parent, int nr) +static void add_handlers(switch_driver *driver, switch_config *handlers, struct proc_dir_entry *parent, int nr)  { +	switch_priv *priv = (switch_priv *) driver->data;  	switch_proc_handler *tmp;  	int i, mode;  	struct proc_dir_entry *p; @@ -142,6 +143,7 @@ static void add_handlers(switch_priv *priv, switch_config *handlers, struct proc  		INIT_LIST_HEAD(&tmp->list);  		tmp->parent = parent;  		tmp->nr = nr; +		tmp->driver = driver;  		memcpy(&tmp->handler, &(handlers[i]), sizeof(switch_config));  		list_add(&tmp->list, &priv->data.list); @@ -192,7 +194,7 @@ static void do_unregister(switch_driver *driver)  	kfree(priv->vlans);  	remove_proc_entry("vlan", priv->driver_dir); -	remove_proc_entry(driver->name, switch_root); +	remove_proc_entry(driver->interface, switch_root);  	if (priv->nr == (drv_num - 1))  		drv_num--; @@ -213,10 +215,9 @@ static int do_register(switch_driver *driver)  	INIT_LIST_HEAD(&priv->data.list);  	priv->nr = drv_num++; -	sprintf(buf, "%d", priv->nr); -	priv->driver_dir = proc_mkdir(buf, switch_root); +	priv->driver_dir = proc_mkdir(driver->interface, switch_root);  	if (driver->driver_handlers != NULL) -		add_handlers(priv, driver->driver_handlers, priv->driver_dir, 0); +		add_handlers(driver, driver->driver_handlers, priv->driver_dir, 0);  	priv->port_dir = proc_mkdir("port", priv->driver_dir);  	priv->ports = kmalloc((driver->ports + 1) * sizeof(struct proc_dir_entry *), GFP_KERNEL); @@ -224,7 +225,7 @@ static int do_register(switch_driver *driver)  		sprintf(buf, "%d", i);  		priv->ports[i] = proc_mkdir(buf, priv->port_dir);  		if (driver->port_handlers != NULL) -			add_handlers(priv, driver->port_handlers, priv->ports[i], i); +			add_handlers(driver, driver->port_handlers, priv->ports[i], i);  	}  	priv->ports[i] = NULL; @@ -234,7 +235,7 @@ static int do_register(switch_driver *driver)  		sprintf(buf, "%d", i);  		priv->vlans[i] = proc_mkdir(buf, priv->vlan_dir);  		if (driver->vlan_handlers != NULL) -			add_handlers(priv, driver->vlan_handlers, priv->vlans[i], i); +			add_handlers(driver, driver->vlan_handlers, priv->vlans[i], i);  	}  	priv->vlans[i] = NULL; @@ -242,7 +243,7 @@ static int do_register(switch_driver *driver)  	return 0;  } -static int isspace(char c) { +static inline int isspace(char c) {  	switch(c) {  		case ' ':  		case 0x09: @@ -298,39 +299,57 @@ int switch_print_media(char *buf, int media)  	return len;  } -int switch_parse_vlan(char *buf) +switch_vlan_config *switch_parse_vlan(switch_driver *driver, char *buf)  { -	char vlan = 0, tag = 0, pvid_port = 0; -	int untag, j; +	switch_vlan_config *c; +	int j, u, p, s; +	 +	c = kmalloc(sizeof(switch_vlan_config), GFP_KERNEL); +	memset(c, 0, sizeof(switch_vlan_config));  	while (isspace(*buf)) buf++; -	 +	j = 0;  	while (*buf >= '0' && *buf <= '9') { -		j = *buf++ - '0'; -		vlan |= 1 << j; -		 -		untag = 0; -		/* untag if needed, CPU port requires special handling */ -		if (*buf == 'u' || (j != 5 && (isspace(*buf) || *buf == 0))) { -			untag = 1; -			if (*buf) buf++; -		} else if (*buf == '*') { -			pvid_port |= (1 << j); -			buf++; -		} else if (*buf == 't' || isspace(*buf)) { -			buf++; -		} else break; - -		if (!untag) -			tag |= 1 << j; +		j *= 10; +		j += *buf++ - '0'; + +		u = ((j == driver->cpuport) ? 0 : 1); +		p = 0; +		s = !(*buf >= '0' && *buf <= '9'); +	 +		if (s) { +			while (s && !isspace(*buf) && (*buf != 0)) { +				switch(*buf) { +					case 'u': +						u = 1; +						break; +					case 't': +						u = 0; +						break; +					case '*': +						p = 1; +						break; +				} +				buf++; +			} +			c->port |= (1 << j); +			if (u) +				c->untag |= (1 << j); +			if (p) +				c->pvid |= (1 << j); + +			j = 0; +		}  		while (isspace(*buf)) buf++;  	} -	 -	if (*buf) -		return -1; +	if (*buf != 0) return NULL; -	return (pvid_port << 16) | (tag << 8) | vlan; +	c->port &= (1 << driver->ports) - 1; +	c->untag &= (1 << driver->ports) - 1; +	c->pvid &= (1 << driver->ports) - 1; +	 +	return c;  } @@ -345,11 +364,16 @@ int switch_register_driver(switch_driver *driver)  			printk("Switch driver '%s' already exists in the kernel\n", driver->name);  			return -EINVAL;  		} +		if (strcmp(list_entry(pos, switch_driver, list)->interface, driver->interface) == 0) { +			printk("There is already a switch registered on the device '%s'\n", driver->interface); +			return -EINVAL; +		}  	}  	new = kmalloc(sizeof(switch_driver), GFP_KERNEL);  	memcpy(new, driver, sizeof(switch_driver));  	new->name = strdup(driver->name); +	new->interface = strdup(driver->interface);  	if ((ret = do_register(new)) < 0) {  		kfree(new->name); diff --git a/target/linux/package/switch/src/switch-core.h b/target/linux/package/switch/src/switch-core.h index 9927e8519..bdf0ae1f8 100644 --- a/target/linux/package/switch/src/switch-core.h +++ b/target/linux/package/switch/src/switch-core.h @@ -17,27 +17,33 @@  #define LINUX_2_4  #endif -typedef int (*switch_handler)(char *buf, int nr); +typedef int (*switch_handler)(void *driver, char *buf, int nr);  typedef struct {  	char *name;  	switch_handler read, write;  } switch_config; -  typedef struct {  	struct list_head list;  	char *name; +	char *interface; +	int cpuport;  	int ports;  	int vlans;  	switch_config *driver_handlers, *port_handlers, *vlan_handlers;  	void *data; +	void *priv;  } switch_driver; +typedef struct { +	u32 port, untag, pvid; +} switch_vlan_config; +  extern int switch_register_driver(switch_driver *driver);  extern void switch_unregister_driver(char *name); -extern int switch_parse_vlan(char *buf); +extern switch_vlan_config *switch_parse_vlan(switch_driver *driver, char *buf);  extern int switch_parse_media(char *buf);  extern int switch_print_media(char *buf, int media); diff --git a/target/linux/package/switch/src/switch-robo.c b/target/linux/package/switch/src/switch-robo.c index d596dc653..57978bce0 100644 --- a/target/linux/package/switch/src/switch-robo.c +++ b/target/linux/package/switch/src/switch-robo.c @@ -56,18 +56,6 @@ static int max_vlans, max_ports;  static struct ifreq ifr;  static struct net_device *dev; -static int isspace(char c) { -	switch(c) { -		case ' ': -		case 0x09: -		case 0x0a: -		case 0x0d: -			return 1; -		default: -			return 0; -	} -} -  static int do_ioctl(int cmd, void *buf)  {  	mm_segment_t old_fs = get_fs(); @@ -297,7 +285,7 @@ static int robo_probe(char *devname)  } -static int handle_vlan_port_read(char *buf, int nr) +static int handle_vlan_port_read(void *driver, char *buf, int nr)  {  	__u16 val16;  	int len = 0; @@ -337,45 +325,34 @@ static int handle_vlan_port_read(char *buf, int nr)  	return len;  } -static int handle_vlan_port_write(char *buf, int nr) +static int handle_vlan_port_write(void *driver, char *buf, int nr)  { -	int untag = 0; -	int member = 0; +	switch_driver *d = (switch_driver *) driver; +	switch_vlan_config *c = switch_parse_vlan(d, buf);  	int j;  	__u16 val16; -	while (*buf >= '0' && *buf <= '9') { -		j = *buf++ - '0'; -		member |= 1 << j; -		 -		/* untag if needed, CPU port requires special handling */ -		if (*buf == 'u' || (j != 5 && (isspace(*buf) || *buf == 0))) { -			untag |= 1 << j; -			if (*buf) buf++; +	if (c == NULL) +		return -EINVAL; + +	for (j = 0; j < d->ports; j++) { +		if ((c->untag | c->pvid) & (1 << j))  			/* change default vlan tag */  			robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_PORT0_DEF_TAG + (j << 1), nr); -		} else if (*buf == '*' || *buf == 't' || isspace(*buf)) { -			buf++; -		} else break; -		 -		while (isspace(*buf)) buf++;  	} -	 -	if (*buf) { -		return -1; + +	/* write config now */ +	val16 = (nr) /* vlan */ | (1 << 12) /* write */ | (1 << 13) /* enable */; +	if (is_5350) { +		robo_write32(ROBO_VLAN_PAGE, ROBO_VLAN_WRITE_5350, +			(1 << 20) /* valid */ | (c->untag << 6) | c->port); +		robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16);  	} else { -		/* write config now */ -		val16 = (nr) /* vlan */ | (1 << 12) /* write */ | (1 << 13) /* enable */; -		if (is_5350) { -			robo_write32(ROBO_VLAN_PAGE, ROBO_VLAN_WRITE_5350, -				(1 << 20) /* valid */ | (untag << 6) | member); -			robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS_5350, val16); -		} else { -			robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_WRITE, -				(1 << 14)  /* valid */ | (untag << 7) | member); -			robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS, val16); -		} +		robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_WRITE, +			(1 << 14)  /* valid */ | (c->untag << 7) | c->port); +		robo_write16(ROBO_VLAN_PAGE, ROBO_VLAN_TABLE_ACCESS, val16);  	} +  	return 0;  } @@ -387,6 +364,7 @@ static int __init robo_init()  	for (device[3] = '0'; (device[3] <= '3') && notfound; device[3]++) {  		notfound = robo_probe(device);  	} +	device[3]--;  	if (notfound)  		return -ENODEV; @@ -397,6 +375,8 @@ static int __init robo_init()  		};  		switch_driver driver = {  			name: DRIVER_NAME, +			interface: device, +			cpuport: max_ports - 1,  			ports: max_ports,  			vlans: max_vlans,  			driver_handlers: NULL, | 
