#define REG_SUPP(x) (((x).m != ((u16)-1)) && ((x).p != (u16)-1))
+struct ip175c_state;
+
/*********** CONSTANTS ***********/
struct register_mappings {
char *NAME;
// set to 1 for 178C, 0 for 175C.
bitnum SIMPLE_VLAN_REGISTERS; // 175C has two vlans per register but 178C has only one.
+
+ // Pointers to functions which manipulate hardware state
+ int (*get_flags)(struct ip175c_state *state);
+ int (*get_state)(struct ip175c_state *state);
+ int (*update_state)(struct ip175c_state *state);
+ int (*set_vlan_mode)(struct ip175c_state *state);
+ int (*reset)(struct ip175c_state *state);
};
+static int ip175c_get_flags(struct ip175c_state *state);
+static int ip175c_get_state(struct ip175c_state *state);
+static int ip175c_update_state(struct ip175c_state *state);
+static int ip175c_set_vlan_mode(struct ip175c_state *state);
+static int ip175c_do_reset(struct ip175c_state *state);
+
static const struct register_mappings IP178C = {
.NAME = "IP178C",
.MODEL_NO = 0x18,
.MII_REGISTER_EN = NOTSUPPORTED,
+ .get_flags = ip175c_get_flags,
+ .get_state = ip175c_get_state,
+ .update_state = ip175c_update_state,
+ .set_vlan_mode = ip175c_set_vlan_mode,
+ .reset = ip175c_do_reset,
};
static const struct register_mappings IP175C = {
.MII_REGISTER_EN = NOTSUPPORTED,
+ .get_flags = ip175c_get_flags,
+ .get_state = ip175c_get_state,
+ .update_state = ip175c_update_state,
+ .set_vlan_mode = ip175c_set_vlan_mode,
+ .reset = ip175c_do_reset,
};
static const struct register_mappings IP175A = {
.MII_REGISTER_EN = {0, 18},
.MII_REGISTER_EN_BIT = 7,
+
+ .get_flags = ip175c_get_flags,
+ .get_state = ip175c_get_state,
+ .update_state = ip175c_update_state,
+ .set_vlan_mode = ip175c_set_vlan_mode,
+ .reset = ip175c_do_reset,
};
}
/** Get only the vlan and router flags on the router **/
-static int get_flags(struct ip175c_state *state)
+static int ip175c_get_flags(struct ip175c_state *state)
{
int val;
}
/** Get all state variables for VLAN mappings and port-based tagging **/
-static int get_state(struct ip175c_state *state)
+static int ip175c_get_state(struct ip175c_state *state)
{
int i, j;
int ret;
- ret = get_flags(state);
+
+ ret = ip175c_get_flags(state);
if (ret < 0) {
return ret;
}
+
GET_PORT_BITS(state, state->remove_tag,
state->regs->REMOVE_TAG_REG, state->regs->REMOVE_TAG_BIT);
GET_PORT_BITS(state, state->add_tag,
}
if (REG_SUPP(state->regs->VLAN_LOOKUP_REG)) {
- for (j=0; j<MAX_PORTS; j++) {
- state->ports[j].shareports = 0; // initialize them in case.
- }
- for (j=0; j<state->regs->NUM_PORTS; j++) {
- reg addr;
- const bitnum *bit_lookup = (j%2==0)?
- state->regs->VLAN_LOOKUP_EVEN_BIT:
- state->regs->VLAN_LOOKUP_ODD_BIT;
- addr = state->regs->VLAN_LOOKUP_REG;
- if (state->regs->SIMPLE_VLAN_REGISTERS) {
- addr.m += j;
- } else {
- switch (j) {
- case 0:
- case 1:
- break;
- case 2:
- case 3:
- addr.m+=1;
- break;
- case 4:
- addr.m+=2;
- break;
- case 5:
- addr = state->regs->VLAN_LOOKUP_REG_5;
- break;
- }
+ for (j=0; j<MAX_PORTS; j++) {
+ state->ports[j].shareports = 0; // initialize them in case.
}
+ for (j=0; j<state->regs->NUM_PORTS; j++) {
+ reg addr;
+ const bitnum *bit_lookup = (j%2==0)?
+ state->regs->VLAN_LOOKUP_EVEN_BIT:
+ state->regs->VLAN_LOOKUP_ODD_BIT;
+ addr = state->regs->VLAN_LOOKUP_REG;
+ if (state->regs->SIMPLE_VLAN_REGISTERS) {
+ addr.m += j;
+ } else {
+ switch (j) {
+ case 0:
+ case 1:
+ break;
+ case 2:
+ case 3:
+ addr.m+=1;
+ break;
+ case 4:
+ addr.m+=2;
+ break;
+ case 5:
+ addr = state->regs->VLAN_LOOKUP_REG_5;
+ break;
+ }
+ }
- if (REG_SUPP(addr)) {
- GET_PORT_BITS(state, state->ports[j].shareports, addr, bit_lookup);
+ if (REG_SUPP(addr)) {
+ GET_PORT_BITS(state, state->ports[j].shareports, addr, bit_lookup);
+ }
}
- }
} else {
for (j=0; j<MAX_PORTS; j++) {
state->ports[j].shareports = 0xff;
return 0;
}
-/** Only update vlan and router flags in the switch **/
-static int update_flags(struct ip175c_state *state)
+/** Only set vlan and router flags in the switch **/
+static int ip175c_set_flags(struct ip175c_state *state)
{
int val;
return setPhy(state, state->regs->ROUTER_CONTROL_REG, val);
}
-/** Update all VLAN and port state. Usually you should call "correct_vlan_state" first. **/
-static int update_state(struct ip175c_state *state)
+/** Set all VLAN and port state. Usually you should call "correct_vlan_state" first. **/
+static int ip175c_set_state(struct ip175c_state *state)
{
int j;
int i;
state->regs->REMOVE_TAG_REG, state->regs->REMOVE_TAG_BIT);
if (REG_SUPP(state->regs->VLAN_LOOKUP_REG)) {
- for (j=0; j<state->regs->NUM_PORTS; j++) {
- reg addr;
- const bitnum *bit_lookup = (j%2==0)?
- state->regs->VLAN_LOOKUP_EVEN_BIT:
- state->regs->VLAN_LOOKUP_ODD_BIT;
-
- // duplicate code -- sorry
- addr = state->regs->VLAN_LOOKUP_REG;
- if (state->regs->SIMPLE_VLAN_REGISTERS) {
- addr.m += j;
- } else {
- switch (j) {
- case 0:
- case 1:
- break;
- case 2:
- case 3:
- addr.m+=1;
- break;
- case 4:
- addr.m+=2;
- break;
- case 5:
- addr = state->regs->VLAN_LOOKUP_REG_5;
- break;
- default:
- addr.m = -1; // shouldn't get here, but...
- break;
+ for (j=0; j<state->regs->NUM_PORTS; j++) {
+ reg addr;
+ const bitnum *bit_lookup = (j%2==0)?
+ state->regs->VLAN_LOOKUP_EVEN_BIT:
+ state->regs->VLAN_LOOKUP_ODD_BIT;
+
+ // duplicate code -- sorry
+ addr = state->regs->VLAN_LOOKUP_REG;
+ if (state->regs->SIMPLE_VLAN_REGISTERS) {
+ addr.m += j;
+ } else {
+ switch (j) {
+ case 0:
+ case 1:
+ break;
+ case 2:
+ case 3:
+ addr.m+=1;
+ break;
+ case 4:
+ addr.m+=2;
+ break;
+ case 5:
+ addr = state->regs->VLAN_LOOKUP_REG_5;
+ break;
+ default:
+ addr.m = -1; // shouldn't get here, but...
+ break;
+ }
+ }
+ //printf("shareports for %d is %02X\n",j,state->ports[j].shareports);
+ if (REG_SUPP(addr)) {
+ SET_PORT_BITS(state, state->ports[j].shareports, addr, bit_lookup);
}
}
- //printf("shareports for %d is %02X\n",j,state->ports[j].shareports);
- if (REG_SUPP(addr)) {
- SET_PORT_BITS(state, state->ports[j].shareports, addr, bit_lookup);
- }
- }
}
if (REG_SUPP(state->regs->TAG_VLAN_MASK_REG)) {
- for (j=0; j<MAX_VLANS; j++) {
- reg addr = state->regs->TAG_VLAN_MASK_REG;
- const bitnum *bit_lookup = (j%2==0)?
- state->regs->TAG_VLAN_MASK_EVEN_BIT:
- state->regs->TAG_VLAN_MASK_ODD_BIT;
- unsigned int vlan_mask;
- if (state->regs->SIMPLE_VLAN_REGISTERS) {
- addr.m += j;
- } else {
- addr.m += j/2;
+ for (j=0; j<MAX_VLANS; j++) {
+ reg addr = state->regs->TAG_VLAN_MASK_REG;
+ const bitnum *bit_lookup = (j%2==0)?
+ state->regs->TAG_VLAN_MASK_EVEN_BIT:
+ state->regs->TAG_VLAN_MASK_ODD_BIT;
+ unsigned int vlan_mask;
+ if (state->regs->SIMPLE_VLAN_REGISTERS) {
+ addr.m += j;
+ } else {
+ addr.m += j/2;
+ }
+ vlan_mask = state->vlan_ports[j];
+ SET_PORT_BITS(state, vlan_mask, addr, bit_lookup);
}
- vlan_mask = state->vlan_ports[j];
- SET_PORT_BITS(state, vlan_mask, addr, bit_lookup);
- }
}
for (i=0; i<MAX_PORTS; i++) {
}
}
- return update_flags(state);
+ return ip175c_set_flags(state);
}
/**
* Uses only the VLAN port mask and the add tag mask to generate the other fields:
* which ports are part of the same VLAN, removing vlan tags, and VLAN tag ids.
*/
-static void correct_vlan_state(struct ip175c_state *state)
+static void ip175c_correct_vlan_state(struct ip175c_state *state)
{
int i, j;
state->num_vlans = 0;
state->remove_tag = ((~state->add_tag) & ((1<<state->regs->NUM_PORTS)-1));
}
+static int ip175c_update_state(struct ip175c_state *state)
+{
+ ip175c_correct_vlan_state(state);
+ return ip175c_set_state(state);
+}
+
+static int ip175c_set_vlan_mode(struct ip175c_state *state)
+{
+ return ip175c_update_state(state);
+}
+
+static int ip175c_do_reset(struct ip175c_state *state)
+{
+ int err;
+
+ if (REG_SUPP(state->regs->MODE_REG)) {
+ err = setPhy(state, state->regs->MODE_REG, state->regs->MODE_VAL);
+ if (err < 0)
+ return err;
+ err = getPhy(state, state->regs->MODE_REG);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
static int ip175c_get_enable_vlan(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
{
struct ip175c_state *state = dev->priv;
int err;
- err = get_state(state); // May be set in get_state.
+ err = state->regs->get_state(state); // May be set in get_state.
if (err < 0)
return err;
val->value.i = state->vlan_enabled;
int enable;
int i;
- err = get_state(state);
+ err = state->regs->get_state(state);
if (err < 0)
return err;
enable = val->value.i;
// Otherwise, if we are switching state, set fields to a known default.
state->remove_tag = 0x0000;
state->add_tag = 0x0000;
- for (i = 0; i < MAX_PORTS; i++)
- state->ports[i].shareports = 0xffff;
-
for (i = 0; i < MAX_VLANS; i++)
state->vlan_ports[i] = 0x0;
- if (state->vlan_enabled) {
- // Updates other fields only based off vlan_ports and add_tag fields.
- // Note that by default, no ports are in any vlans.
- correct_vlan_state(state);
- }
- // Ensure sane defaults?
- return update_state(state);
+ return state->regs->set_vlan_mode(state);
}
static int ip175c_get_ports(struct switch_dev *dev, struct switch_val *val)
if (val->port_vlan >= dev->vlans || val->port_vlan < 0)
return -EINVAL;
- err = get_state(state);
+ err = state->regs->get_state(state);
if (err<0)
return err;
if (val->port_vlan >= dev->vlans || val->port_vlan < 0)
return -EINVAL;
- err = get_state(state);
+ err = state->regs->get_state(state);
if (err < 0)
return err;
}
}
- correct_vlan_state(state);
- err = update_state(state);
-
- return err;
+ return state->regs->update_state(state);
}
static int ip175c_apply(struct switch_dev *dev)
struct ip175c_state *state = dev->priv;
int err;
- err = get_flags(state);
+ err = state->regs->get_flags(state);
if (err < 0)
return err;
struct ip175c_state *state = dev->priv;
int i, err;
- err = get_flags(state);
+ err = state->regs->get_flags(state);
if (err < 0)
return err;
mdelay(2);
}
- if (REG_SUPP(state->regs->MODE_REG)) {
- err = setPhy(state, state->regs->MODE_REG, state->regs->RESET_VAL);
- if (err < 0)
- return err;
- err = getPhy(state, state->regs->MODE_REG);
- }
-
/* reset switch ports */
for (i = 0; i < state->regs->NUM_PORTS-1; i++) {
err = ip_phy_write(state, i, MII_BMCR, BMCR_RESET);
return err;
}
- return 0;
+ return state->regs->reset(state);
}
static int ip175c_get_tagged(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
struct ip175c_state *state = dev->priv;
int err;
- err = get_state(state);
+ err = state->regs->get_state(state);
if (err < 0)
return err;
struct ip175c_state *state = dev->priv;
int err;
- err = get_state(state);
+ err = state->regs->get_state(state);
if (err < 0)
return err;
if (val->value.i == 1)
state->add_tag |= (1<<val->port_vlan);
- SET_PORT_BITS(state, state->add_tag,
- state->regs->ADD_TAG_REG, state->regs->ADD_TAG_BIT);
- SET_PORT_BITS(state, state->remove_tag,
- state->regs->REMOVE_TAG_REG, state->regs->REMOVE_TAG_BIT);
-
- return err;
+ return state->regs->update_state(state);
}
/** Get the current phy address */
static int ip175c_set_val(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
{
struct ip175c_state *state = dev->priv;
- int myval, err = 0;
+ int myval, err = -EINVAL;
myval = val->value.i;
if (myval <= 0xffff && myval >= 0 && REG_SUPP(state->proc_mii)) {
static int ip175c_set_pvid(struct switch_dev *dev, int port, int val)
{
struct ip175c_state *state = dev->priv;
+ int err;
- state->ports[port].pvid = val;
+ if (val < 0 || val >= MAX_VLANS)
+ return -EINVAL;
- if (!REG_SUPP(state->regs->VLAN_DEFAULT_TAG_REG[port]))
- return 0;
+ err = state->regs->get_state(state);
+ if (err < 0)
+ return err;
+
+ state->ports[port].pvid = val;
- return setPhy(state, state->regs->VLAN_DEFAULT_TAG_REG[port], val);
+ return state->regs->update_state(state);
}