aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--target/linux/generic-2.6/files/drivers/net/phy/ip175c.c170
1 files changed, 169 insertions, 1 deletions
diff --git a/target/linux/generic-2.6/files/drivers/net/phy/ip175c.c b/target/linux/generic-2.6/files/drivers/net/phy/ip175c.c
index ef4b4d9092..3f21d72b66 100644
--- a/target/linux/generic-2.6/files/drivers/net/phy/ip175c.c
+++ b/target/linux/generic-2.6/files/drivers/net/phy/ip175c.c
@@ -263,6 +263,56 @@ static const struct register_mappings IP175A = {
};
+static int ip175d_get_flags(struct ip175c_state *state);
+static int ip175d_get_state(struct ip175c_state *state);
+static int ip175d_update_state(struct ip175c_state *state);
+static int ip175d_set_vlan_mode(struct ip175c_state *state);
+static int ip175d_reset(struct ip175c_state *state);
+
+static const struct register_mappings IP175D = {
+ .NAME = "IP175D",
+ .MODEL_NO = 0x18,
+
+ // The IP175D has a completely different interface, so we leave most
+ // of the registers undefined and switch to different code paths.
+
+ .VLAN_DEFAULT_TAG_REG = {
+ NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,
+ NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,NOTSUPPORTED,
+ },
+
+ .ADD_TAG_REG = NOTSUPPORTED,
+ .REMOVE_TAG_REG = NOTSUPPORTED,
+
+ .SIMPLE_VLAN_REGISTERS = 0,
+
+ .VLAN_LOOKUP_REG = NOTSUPPORTED,
+ .VLAN_LOOKUP_REG_5 = NOTSUPPORTED,
+ .TAG_VLAN_MASK_REG = NOTSUPPORTED,
+
+ .RESET_VAL = 0x175D,
+ .RESET_REG = {20,2},
+ .MODE_REG = NOTSUPPORTED,
+
+ .ROUTER_CONTROL_REG = NOTSUPPORTED,
+ .ROUTER_EN_BIT = -1,
+ .NUMLAN_GROUPS_BIT = -1,
+
+ .VLAN_CONTROL_REG = NOTSUPPORTED,
+ .TAG_VLAN_BIT = -1,
+
+ .NUM_PORTS = 6,
+ .CPU_PORT = 5,
+
+ .MII_REGISTER_EN = NOTSUPPORTED,
+
+ .get_flags = ip175d_get_flags,
+ .get_state = ip175d_get_state,
+ .update_state = ip175d_update_state,
+ .set_vlan_mode = ip175d_set_vlan_mode,
+ .reset = ip175d_reset,
+};
+
struct ip175c_state {
struct switch_dev dev;
struct mii_bus *mii_bus;
@@ -407,7 +457,7 @@ static int get_model(struct ip175c_state *state)
chip_no = ip_phy_read(state, 20, 0);
pr_debug("IP175C: Chip ID register reads %04x\n", chip_no);
if (chip_no == 0x175d) {
- state->regs = &IP175C;
+ state->regs = &IP175D;
} else {
state->regs = &IP175C;
}
@@ -419,6 +469,8 @@ static int get_model(struct ip175c_state *state)
return 0;
}
+/*** Low-level functions for the older models ***/
+
/** Get only the vlan and router flags on the router **/
static int ip175c_get_flags(struct ip175c_state *state)
{
@@ -727,6 +779,122 @@ static int ip175c_do_reset(struct ip175c_state *state)
return 0;
}
+/*** Low-level functions for IP175D ***/
+
+static int ip175d_get_flags(struct ip175c_state *state)
+{
+ // We keep the configuration of the switch cached, so get doesn't do anything
+ return 0;
+}
+
+static int ip175d_get_state(struct ip175c_state *state)
+{
+ // Again, the configuration is fully cached
+ return 0;
+}
+
+static int ip175d_update_state(struct ip175c_state *state)
+{
+ unsigned int filter_mask = 0;
+ unsigned int ports[16], add[16], rem[16];
+ int i, j;
+ int err = 0;
+
+ for (i = 0; i < 16; i++) {
+ ports[i] = 0;
+ add[i] = 0;
+ rem[i] = 0;
+ if (!state->vlan_enabled) {
+ err |= ip_phy_write(state, 22, 14+i, i+1); // default tags
+ ports[i] = 0x3f;
+ continue;
+ }
+ if (!state->vlans[i].tag) {
+ // Reset the filter
+ err |= ip_phy_write(state, 22, 14+i, 0); // tag
+ continue;
+ }
+ filter_mask |= 1 << i;
+ err |= ip_phy_write(state, 22, 14+i, state->vlans[i].tag);
+ ports[i] = state->vlans[i].ports;
+ for (j = 0; j < 6; j++) {
+ if (ports[i] & (1 << j)) {
+ if (state->add_tag & (1 << j))
+ add[i] |= 1 << j;
+ if (state->remove_tag & (1 << j))
+ rem[i] |= 1 << j;
+ }
+ }
+ }
+
+ // Port masks, tag adds and removals
+ for (i = 0; i < 8; i++) {
+ err |= ip_phy_write(state, 23, i, ports[2*i] | (ports[2*i+1] << 8));
+ err |= ip_phy_write(state, 23, 8+i, add[2*i] | (add[2*i+1] << 8));
+ err |= ip_phy_write(state, 23, 16+i, rem[2*i] | (rem[2*i+1] << 8));
+ }
+ err |= ip_phy_write(state, 22, 10, filter_mask);
+
+ // Default VLAN tag for each port
+ for (i = 0; i < 6; i++)
+ err |= ip_phy_write(state, 22, 4+i, state->vlans[state->ports[i].pvid].tag);
+
+ return (err ? -EIO : 0);
+}
+
+static int ip175d_set_vlan_mode(struct ip175c_state *state)
+{
+ int i;
+ int err = 0;
+
+ if (state->vlan_enabled) {
+ // VLAN classification rules: tag-based VLANs, use VID to classify,
+ // drop packets that cannot be classified.
+ err |= ip_phy_write_masked(state, 22, 0, 0x3fff, 0x003f);
+
+ // Ingress rules: CFI=1 dropped, null VID is untagged, VID=1 passed,
+ // VID=0xfff discarded, admin both tagged and untagged, ingress
+ // filters enabled.
+ err |= ip_phy_write_masked(state, 22, 1, 0x0fff, 0x0c3f);
+
+ // Egress rules: IGMP processing off, keep VLAN header off
+ err |= ip_phy_write_masked(state, 22, 2, 0x0fff, 0x0000);
+ } else {
+ // VLAN classification rules: everything off & clear table
+ err |= ip_phy_write_masked(state, 22, 0, 0xbfff, 0x8000);
+
+ // Ingress and egress rules: set to defaults
+ err |= ip_phy_write_masked(state, 22, 1, 0x0fff, 0x0c3f);
+ err |= ip_phy_write_masked(state, 22, 2, 0x0fff, 0x0000);
+ }
+
+ // Reset default VLAN for each port to 0
+ for (i = 0; i < 6; i++)
+ state->ports[i].pvid = 0;
+
+ err |= ip175d_update_state(state);
+
+ return (err ? -EIO : 0);
+}
+
+static int ip175d_reset(struct ip175c_state *state)
+{
+ int err = 0;
+
+ // Disable the special tagging mode
+ err |= ip_phy_write_masked(state, 21, 22, 0x0003, 0x0000);
+
+ // Set 802.1q protocol type
+ err |= ip_phy_write(state, 22, 3, 0x8100);
+
+ state->vlan_enabled = 0;
+ err |= ip175d_set_vlan_mode(state);
+
+ return (err ? -EIO : 0);
+}
+
+/*** High-level functions ***/
+
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;