ip17xx: Introduce indirection of low-level operations
This patch introduces seperation between low-level and high-level parts of the driver. The low-level functions are now called via pointers stored in struct ip175c_regs. The only functional changes are: o correct_vlan_state() is now called as a part of every update_state(). o The order of setting of MODE_REG and resetting switch ports has changed. (These are independent actions, so it should not matter.) o ip175c_set_tagged() sets the tags via update_state() instead of writing directly to the registers. o The same for ip175c_set_pvid(). The only gaps in this abstraction are operations on ports (get_port_speed and friends), which access PHY registers directly. Signed-off-by: Martin Mares <mj@ucw.cz> Signed-off-by: Patrick Horn <patrick.horn@gmail.com> git-svn-id: svn://svn.openwrt.org/openwrt/trunk@21714 3c298f89-4303-0410-b956-a3cf2f4a3e73master
parent
ce244e155a
commit
83ae20132e
|
@ -40,6 +40,8 @@ typedef char bitnum;
|
||||||
|
|
||||||
#define REG_SUPP(x) (((x).m != ((u16)-1)) && ((x).p != (u16)-1))
|
#define REG_SUPP(x) (((x).m != ((u16)-1)) && ((x).p != (u16)-1))
|
||||||
|
|
||||||
|
struct ip175c_state;
|
||||||
|
|
||||||
/*********** CONSTANTS ***********/
|
/*********** CONSTANTS ***********/
|
||||||
struct register_mappings {
|
struct register_mappings {
|
||||||
char *NAME;
|
char *NAME;
|
||||||
|
@ -96,8 +98,21 @@ struct register_mappings {
|
||||||
|
|
||||||
// set to 1 for 178C, 0 for 175C.
|
// set to 1 for 178C, 0 for 175C.
|
||||||
bitnum SIMPLE_VLAN_REGISTERS; // 175C has two vlans per register but 178C has only one.
|
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 = {
|
static const struct register_mappings IP178C = {
|
||||||
.NAME = "IP178C",
|
.NAME = "IP178C",
|
||||||
.MODEL_NO = 0x18,
|
.MODEL_NO = 0x18,
|
||||||
|
@ -140,6 +155,11 @@ static const struct register_mappings IP178C = {
|
||||||
|
|
||||||
.MII_REGISTER_EN = NOTSUPPORTED,
|
.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 = {
|
static const struct register_mappings IP175C = {
|
||||||
|
@ -184,6 +204,11 @@ static const struct register_mappings IP175C = {
|
||||||
|
|
||||||
.MII_REGISTER_EN = NOTSUPPORTED,
|
.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 = {
|
static const struct register_mappings IP175A = {
|
||||||
|
@ -228,6 +253,12 @@ static const struct register_mappings IP175A = {
|
||||||
|
|
||||||
.MII_REGISTER_EN = {0, 18},
|
.MII_REGISTER_EN = {0, 18},
|
||||||
.MII_REGISTER_EN_BIT = 7,
|
.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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -385,7 +416,7 @@ static int get_model(struct ip175c_state *state)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get only the vlan and router flags on the router **/
|
/** 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;
|
int val;
|
||||||
|
|
||||||
|
@ -421,14 +452,16 @@ static int get_flags(struct ip175c_state *state)
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get all state variables for VLAN mappings and port-based tagging **/
|
/** 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 i, j;
|
||||||
int ret;
|
int ret;
|
||||||
ret = get_flags(state);
|
|
||||||
|
ret = ip175c_get_flags(state);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
GET_PORT_BITS(state, state->remove_tag,
|
GET_PORT_BITS(state, state->remove_tag,
|
||||||
state->regs->REMOVE_TAG_REG, state->regs->REMOVE_TAG_BIT);
|
state->regs->REMOVE_TAG_REG, state->regs->REMOVE_TAG_BIT);
|
||||||
GET_PORT_BITS(state, state->add_tag,
|
GET_PORT_BITS(state, state->add_tag,
|
||||||
|
@ -519,8 +552,8 @@ static int get_state(struct ip175c_state *state)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Only update vlan and router flags in the switch **/
|
/** Only set vlan and router flags in the switch **/
|
||||||
static int update_flags(struct ip175c_state *state)
|
static int ip175c_set_flags(struct ip175c_state *state)
|
||||||
{
|
{
|
||||||
int val;
|
int val;
|
||||||
|
|
||||||
|
@ -557,8 +590,8 @@ static int update_flags(struct ip175c_state *state)
|
||||||
return setPhy(state, state->regs->ROUTER_CONTROL_REG, val);
|
return setPhy(state, state->regs->ROUTER_CONTROL_REG, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Update all VLAN and port state. Usually you should call "correct_vlan_state" first. **/
|
/** Set all VLAN and port state. Usually you should call "correct_vlan_state" first. **/
|
||||||
static int update_state(struct ip175c_state *state)
|
static int ip175c_set_state(struct ip175c_state *state)
|
||||||
{
|
{
|
||||||
int j;
|
int j;
|
||||||
int i;
|
int i;
|
||||||
|
@ -631,14 +664,14 @@ static int update_state(struct ip175c_state *state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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:
|
* 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.
|
* 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;
|
int i, j;
|
||||||
state->num_vlans = 0;
|
state->num_vlans = 0;
|
||||||
|
@ -664,12 +697,39 @@ static void correct_vlan_state(struct ip175c_state *state)
|
||||||
state->remove_tag = ((~state->add_tag) & ((1<<state->regs->NUM_PORTS)-1));
|
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)
|
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;
|
struct ip175c_state *state = dev->priv;
|
||||||
int err;
|
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)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
val->value.i = state->vlan_enabled;
|
val->value.i = state->vlan_enabled;
|
||||||
|
@ -683,7 +743,7 @@ static int ip175c_set_enable_vlan(struct switch_dev *dev, const struct switch_at
|
||||||
int enable;
|
int enable;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
err = get_state(state);
|
err = state->regs->get_state(state);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
enable = val->value.i;
|
enable = val->value.i;
|
||||||
|
@ -697,19 +757,10 @@ static int ip175c_set_enable_vlan(struct switch_dev *dev, const struct switch_at
|
||||||
// Otherwise, if we are switching state, set fields to a known default.
|
// Otherwise, if we are switching state, set fields to a known default.
|
||||||
state->remove_tag = 0x0000;
|
state->remove_tag = 0x0000;
|
||||||
state->add_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++)
|
for (i = 0; i < MAX_VLANS; i++)
|
||||||
state->vlan_ports[i] = 0x0;
|
state->vlan_ports[i] = 0x0;
|
||||||
|
|
||||||
if (state->vlan_enabled) {
|
return state->regs->set_vlan_mode(state);
|
||||||
// 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ip175c_get_ports(struct switch_dev *dev, struct switch_val *val)
|
static int ip175c_get_ports(struct switch_dev *dev, struct switch_val *val)
|
||||||
|
@ -723,7 +774,7 @@ static int ip175c_get_ports(struct switch_dev *dev, struct switch_val *val)
|
||||||
if (val->port_vlan >= dev->vlans || val->port_vlan < 0)
|
if (val->port_vlan >= dev->vlans || val->port_vlan < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
err = get_state(state);
|
err = state->regs->get_state(state);
|
||||||
if (err<0)
|
if (err<0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -754,7 +805,7 @@ static int ip175c_set_ports(struct switch_dev *dev, struct switch_val *val)
|
||||||
if (val->port_vlan >= dev->vlans || val->port_vlan < 0)
|
if (val->port_vlan >= dev->vlans || val->port_vlan < 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
err = get_state(state);
|
err = state->regs->get_state(state);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -769,10 +820,7 @@ static int ip175c_set_ports(struct switch_dev *dev, struct switch_val *val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
correct_vlan_state(state);
|
return state->regs->update_state(state);
|
||||||
err = update_state(state);
|
|
||||||
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ip175c_apply(struct switch_dev *dev)
|
static int ip175c_apply(struct switch_dev *dev)
|
||||||
|
@ -780,7 +828,7 @@ static int ip175c_apply(struct switch_dev *dev)
|
||||||
struct ip175c_state *state = dev->priv;
|
struct ip175c_state *state = dev->priv;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = get_flags(state);
|
err = state->regs->get_flags(state);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -800,7 +848,7 @@ static int ip175c_reset(struct switch_dev *dev)
|
||||||
struct ip175c_state *state = dev->priv;
|
struct ip175c_state *state = dev->priv;
|
||||||
int i, err;
|
int i, err;
|
||||||
|
|
||||||
err = get_flags(state);
|
err = state->regs->get_flags(state);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -818,13 +866,6 @@ static int ip175c_reset(struct switch_dev *dev)
|
||||||
mdelay(2);
|
mdelay(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* reset switch ports */
|
/* reset switch ports */
|
||||||
for (i = 0; i < state->regs->NUM_PORTS-1; i++) {
|
for (i = 0; i < state->regs->NUM_PORTS-1; i++) {
|
||||||
err = ip_phy_write(state, i, MII_BMCR, BMCR_RESET);
|
err = ip_phy_write(state, i, MII_BMCR, BMCR_RESET);
|
||||||
|
@ -832,7 +873,7 @@ static int ip175c_reset(struct switch_dev *dev)
|
||||||
return err;
|
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)
|
static int ip175c_get_tagged(struct switch_dev *dev, const struct switch_attr *attr, struct switch_val *val)
|
||||||
|
@ -840,7 +881,7 @@ static int ip175c_get_tagged(struct switch_dev *dev, const struct switch_attr *a
|
||||||
struct ip175c_state *state = dev->priv;
|
struct ip175c_state *state = dev->priv;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = get_state(state);
|
err = state->regs->get_state(state);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -863,7 +904,7 @@ static int ip175c_set_tagged(struct switch_dev *dev, const struct switch_attr *a
|
||||||
struct ip175c_state *state = dev->priv;
|
struct ip175c_state *state = dev->priv;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = get_state(state);
|
err = state->regs->get_state(state);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
|
@ -875,12 +916,7 @@ static int ip175c_set_tagged(struct switch_dev *dev, const struct switch_attr *a
|
||||||
if (val->value.i == 1)
|
if (val->value.i == 1)
|
||||||
state->add_tag |= (1<<val->port_vlan);
|
state->add_tag |= (1<<val->port_vlan);
|
||||||
|
|
||||||
SET_PORT_BITS(state, state->add_tag,
|
return state->regs->update_state(state);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Get the current phy address */
|
/** Get the current phy address */
|
||||||
|
@ -1082,13 +1118,18 @@ static int ip175c_get_pvid(struct switch_dev *dev, int port, int *val)
|
||||||
static int ip175c_set_pvid(struct switch_dev *dev, int port, int val)
|
static int ip175c_set_pvid(struct switch_dev *dev, int port, int val)
|
||||||
{
|
{
|
||||||
struct ip175c_state *state = dev->priv;
|
struct ip175c_state *state = dev->priv;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (val < 0 || val >= MAX_VLANS)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
err = state->regs->get_state(state);
|
||||||
|
if (err < 0)
|
||||||
|
return err;
|
||||||
|
|
||||||
state->ports[port].pvid = val;
|
state->ports[port].pvid = val;
|
||||||
|
|
||||||
if (!REG_SUPP(state->regs->VLAN_DEFAULT_TAG_REG[port]))
|
return state->regs->update_state(state);
|
||||||
return 0;
|
|
||||||
|
|
||||||
return setPhy(state, state->regs->VLAN_DEFAULT_TAG_REG[port], val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue