diff options
author | Jason Wright <jason@cvs.openbsd.org> | 2001-05-08 03:52:44 +0000 |
---|---|---|
committer | Jason Wright <jason@cvs.openbsd.org> | 2001-05-08 03:52:44 +0000 |
commit | d44f5d424a2636a3e2d549b3995aaf303d9aafa6 (patch) | |
tree | 347b6e2af211437236e98cec14599395a0536220 /sys/dev | |
parent | ff531edc502f594a3e177b06fedd4a86fe2eb3cd (diff) |
- add support for hardware vlan tag insertion and removal
- add necessary definitions for extension descriptors, missing commands,
and offload capabilities
- rework command/response (again) to allow for long responses (still need
support for long commands, though).
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/pci/if_txp.c | 155 | ||||
-rw-r--r-- | sys/dev/pci/if_txpreg.h | 25 |
2 files changed, 165 insertions, 15 deletions
diff --git a/sys/dev/pci/if_txp.c b/sys/dev/pci/if_txp.c index 5bec3cdb15e..13b4f31d207 100644 --- a/sys/dev/pci/if_txp.c +++ b/sys/dev/pci/if_txp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: if_txp.c,v 1.23 2001/05/03 05:22:51 jason Exp $ */ +/* $OpenBSD: if_txp.c,v 1.24 2001/05/08 03:52:43 jason Exp $ */ /* * Copyright (c) 2001 @@ -116,9 +116,13 @@ void txp_set_filter __P((struct txp_softc *)); int txp_cmd_desc_numfree __P((struct txp_softc *)); int txp_command __P((struct txp_softc *, u_int16_t, u_int16_t, u_int32_t, u_int32_t, u_int16_t *, u_int32_t *, u_int32_t *, int)); +int txp_command2 __P((struct txp_softc *, u_int16_t, u_int16_t, u_int32_t, + u_int32_t, struct txp_rsp_desc **, int)); int txp_response __P((struct txp_softc *, u_int32_t, u_int16_t, u_int16_t, struct txp_rsp_desc **)); -void txp_rsp_fixup __P((struct txp_softc *, struct txp_rsp_desc *)); +void txp_rsp_fixup __P((struct txp_softc *, struct txp_rsp_desc *, + struct txp_rsp_desc *)); +void txp_vlan_enable __P((struct txp_softc *)); void txp_ifmedia_sts __P((struct ifnet *, struct ifmediareq *)); int txp_ifmedia_upd __P((struct ifnet *)); @@ -233,6 +237,10 @@ txp_attach(parent, self, aux) txp_set_filter(sc); +#if NVLAN > 0 + txp_vlan_enable(sc); +#endif + sc->sc_arpcom.ac_enaddr[0] = ((u_int8_t *)&p1)[1]; sc->sc_arpcom.ac_enaddr[1] = ((u_int8_t *)&p1)[0]; sc->sc_arpcom.ac_enaddr[2] = ((u_int8_t *)&p2)[3]; @@ -608,6 +616,14 @@ txp_rx_reclaim(sc, r) m_adj(m, sizeof(struct ether_header)); +#if NVLAN > 0 + if (rxd->rx_stat & RX_STAT_VLAN) { + if (vlan_input_tag(eh, m, htons(rxd->rx_vlan >> 16)) < 0) + ifp->if_noproto++; + goto next; + } +#endif + ether_input(ifp, eh, m); next: @@ -1129,6 +1145,9 @@ txp_start(ifp) struct txp_frag_desc *fxd; struct mbuf *m; u_int32_t firstprod, firstcnt, prod, cnt; +#if NVLAN > 0 + struct ifvlan *ifv; +#endif if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) return; @@ -1164,6 +1183,15 @@ txp_start(ifp) txd->tx_totlen = 0; txd->tx_pflags = 0; +#if NVLAN > 0 + if ((m->m_flags & (M_PROTO1|M_PKTHDR)) == (M_PROTO1|M_PKTHDR) && + m->m_pkthdr.rcvif != NULL) { + ifv = m->m_pkthdr.rcvif->if_softc; + txd->tx_pflags = TX_PFLAGS_VLAN | + (htons(ifv->ifv_tag) << TX_PFLAGS_VLANTAG_S); + } +#endif + fxd = (struct txp_frag_desc *)(r->r_desc + prod); while (m != NULL) { if (m->m_len == 0) { @@ -1207,7 +1235,7 @@ oactive: } /* - * XXX this needs to have a callback mechanism + * Handle simple commands sent to the typhoon */ int txp_command(sc, id, in1, in2, in3, out1, out2, out3, wait) @@ -1263,6 +1291,8 @@ txp_command(sc, id, in1, in2, in3, out1, out2, out3, wait) } if (i == 1000 || rsp == NULL) { printf("%s: 0x%x command failed\n", TXP_DEVNAME(sc), id); + if (rsp != NULL) + free(rsp, M_DEVBUF); return (-1); } @@ -1273,10 +1303,67 @@ txp_command(sc, id, in1, in2, in3, out1, out2, out3, wait) if (out3 != NULL) *out3 = rsp->rsp_par3; - idx += sizeof(struct txp_rsp_desc); - if (idx == sc->sc_rspring.size) + free(rsp, M_DEVBUF); + + return (0); +} + +int +txp_command2(sc, id, in1, in2, in3, rspp, wait) + struct txp_softc *sc; + u_int16_t id, in1; + u_int32_t in2, in3; + struct txp_rsp_desc **rspp; + int wait; +{ + struct txp_hostvar *hv = sc->sc_hostvar; + struct txp_cmd_desc *cmd; + u_int32_t idx, i; + u_int16_t seq; + + if (txp_cmd_desc_numfree(sc) == 0) { + printf("%s: no free cmd descriptors\n", TXP_DEVNAME(sc)); + return (-1); + } + + idx = sc->sc_cmdring.lastwrite; + cmd = (struct txp_cmd_desc *)(((u_int8_t *)sc->sc_cmdring.base) + idx); + bzero(cmd, sizeof(*cmd)); + + cmd->cmd_numdesc = 0; + cmd->cmd_seq = seq = sc->sc_seq++; + cmd->cmd_id = id; + cmd->cmd_par1 = in1; + cmd->cmd_par2 = in2; + cmd->cmd_par3 = in3; + cmd->cmd_flags = CMD_FLAGS_TYPE_CMD | + (wait ? CMD_FLAGS_RESP : 0) | CMD_FLAGS_VALID; + + idx += sizeof(struct txp_cmd_desc); + if (idx == sc->sc_cmdring.size) idx = 0; - sc->sc_rspring.lastwrite = hv->hv_resp_read_idx = idx; + sc->sc_cmdring.lastwrite = idx; + + WRITE_REG(sc, TXP_H2A_2, sc->sc_cmdring.lastwrite); + + if (!wait) + return (0); + + for (i = 0; i < 10000; i++) { + idx = hv->hv_resp_read_idx; + if (idx != hv->hv_resp_write_idx) { + *rspp = NULL; + if (txp_response(sc, idx, cmd->cmd_id, seq, rspp)) + return (-1); + if (*rspp != NULL) + break; + } + DELAY(50); + } + if (i == 1000 || (*rspp) == NULL) { + printf("%s: 0x%x command failed\n", TXP_DEVNAME(sc), id); + return (-1); + } return (0); } @@ -1296,13 +1383,18 @@ txp_response(sc, ridx, id, seq, rspp) rsp = (struct txp_rsp_desc *)(((u_int8_t *)sc->sc_rspring.base) + ridx); if (id == rsp->rsp_id && rsp->rsp_seq == seq) { - *rspp = rsp; + *rspp = (struct txp_rsp_desc *)malloc( + sizeof(struct txp_rsp_desc) * (rsp->rsp_numdesc + 1), + M_DEVBUF, M_NOWAIT); + if ((*rspp) == NULL) + return (-1); + txp_rsp_fixup(sc, rsp, *rspp); return (0); } if (rsp->rsp_flags & RSP_FLAGS_ERROR) { printf("%s: response error!\n", TXP_DEVNAME(sc)); - txp_rsp_fixup(sc, rsp); + txp_rsp_fixup(sc, rsp, NULL); ridx = hv->hv_resp_read_idx; continue; } @@ -1321,7 +1413,7 @@ txp_response(sc, ridx, id, seq, rspp) rsp->rsp_id); } - txp_rsp_fixup(sc, rsp); + txp_rsp_fixup(sc, rsp, NULL); ridx = hv->hv_resp_read_idx; hv->hv_resp_read_idx = ridx; } @@ -1330,19 +1422,25 @@ txp_response(sc, ridx, id, seq, rspp) } void -txp_rsp_fixup(sc, rsp) +txp_rsp_fixup(sc, rsp, dst) struct txp_softc *sc; - struct txp_rsp_desc *rsp; + struct txp_rsp_desc *rsp, *dst; { + struct txp_rsp_desc *src = rsp; struct txp_hostvar *hv = sc->sc_hostvar; u_int32_t i, ridx; ridx = hv->hv_resp_read_idx; for (i = 0; i < rsp->rsp_numdesc + 1; i++) { + if (dst != NULL) + bcopy(src, dst++, sizeof(struct txp_rsp_desc)); ridx += sizeof(struct txp_rsp_desc); - if (ridx == sc->sc_rspring.size) + if (ridx == sc->sc_rspring.size) { + src = sc->sc_rspring.base; ridx = 0; + } else + src++; sc->sc_rspring.lastwrite = hv->hv_resp_read_idx = ridx; } @@ -1614,3 +1712,36 @@ setit: txp_command(sc, TXP_CMD_RX_FILTER_WRITE, filter, 0, 0, NULL, NULL, NULL, 1); } + +void +txp_vlan_enable(sc) + struct txp_softc *sc; +{ + struct txp_rsp_desc *rsp = NULL; + struct txp_ext_desc *ext; + + /* Setup type filter */ + if (txp_command(sc, TXP_CMD_VLAN_ETHER_TYPE_WRITE, ETHERTYPE_8021Q, + 0, 0, NULL, NULL, NULL, 1)) + goto out; + + /* + * Try to enable VLAN offload capability + */ + if (txp_command2(sc, TXP_CMD_OFFLOAD_READ, 0, 0, 0, &rsp, 1)) + goto out; + + if (rsp->rsp_numdesc != 1) + goto out; + ext = (struct txp_ext_desc *)(rsp + 1); + + if (txp_command(sc, TXP_CMD_OFFLOAD_WRITE, 0, + (ext->ext_1 | OFFLOAD_VLAN) & rsp->rsp_par2, + (ext->ext_2 | OFFLOAD_VLAN) & rsp->rsp_par3, + NULL, NULL, NULL, 1)) + goto out; + +out: + if (rsp != NULL) + free(rsp, M_DEVBUF); +} diff --git a/sys/dev/pci/if_txpreg.h b/sys/dev/pci/if_txpreg.h index e20eb569c93..a4abf44b03a 100644 --- a/sys/dev/pci/if_txpreg.h +++ b/sys/dev/pci/if_txpreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: if_txpreg.h,v 1.20 2001/05/03 05:22:51 jason Exp $ */ +/* $OpenBSD: if_txpreg.h,v 1.21 2001/05/08 03:52:43 jason Exp $ */ /* * Copyright (c) 2001 Aaron Campbell <aaron@monkey.org>. @@ -165,6 +165,7 @@ #define TXP_CMD_GET_IP_ADDRESS 0x4a #define TXP_CMD_READ_PCI_REG 0x4c #define TXP_CMD_WRITE_PCI_REG 0x4d +#define TXP_CMD_OFFLOAD_READ 0x4e #define TXP_CMD_OFFLOAD_WRITE 0x4f #define TXP_CMD_HELLO_RESPONSE 0x57 #define TXP_CMD_ENABLE_RX_FILTER 0x58 @@ -247,9 +248,9 @@ struct txp_tx_desc { #define TX_PFLAGS_PRIO 0x00000040 /* priority field valid */ #define TX_PFLAGS_UDPCKSUM 0x00000080 /* udp checksum */ #define TX_PFLAGS_PADFRAME 0x00000100 /* pad frame */ -#define TX_PFLAGS_VLANTAG_M 0x000ff000 /* vlan tag mask */ +#define TX_PFLAGS_VLANTAG_M 0x0ffff000 /* vlan tag mask */ #define TX_PFLAGS_VLANPRI_M 0x00700000 /* vlan priority mask */ -#define TX_PFLAGS_VLANTAG_S 16 /* amount to shift tag */ +#define TX_PFLAGS_VLANTAG_S 12 /* amount to shift tag */ struct txp_rx_desc { volatile u_int8_t rx_flags; /* type/descriptor flags */ @@ -310,6 +311,14 @@ struct txp_rxbuf_desc { volatile u_int32_t rb_vaddrhi; }; +/* Extension descriptor */ +struct txp_ext_desc { + volatile u_int32_t ext_1; + volatile u_int32_t ext_2; + volatile u_int32_t ext_3; + volatile u_int32_t ext_4; +}; + struct txp_cmd_desc { volatile u_int8_t cmd_flags; volatile u_int8_t cmd_numdesc; @@ -497,6 +506,16 @@ struct txp_hostvar { #define CMD_ENTRIES 32 #define RSP_ENTRIES 32 +#define OFFLOAD_TCPCKSUM 0x00000002 /* tcp checksum */ +#define OFFLOAD_UDPCKSUM 0x00000004 /* udp checksum */ +#define OFFLOAD_IPCKSUM 0x00000008 /* ip checksum */ +#define OFFLOAD_IPSEC 0x00000010 /* ipsec enable */ +#define OFFLOAD_BCAST 0x00000020 /* broadcast throttle */ +#define OFFLOAD_DHCP 0x00000040 /* dhcp prevention */ +#define OFFLOAD_VLAN 0x00000080 /* vlan enable */ +#define OFFLOAD_FILTER 0x00000100 /* filter enable */ +#define OFFLOAD_TCPSEG 0x00000200 /* tcp segmentation */ + /* * Macros for converting array indices to offsets within the descriptor * arrays. The chip operates on offsets, but it's much easier for us |