nlge (alternate XLR GMAC driver) updates:

- Updates for the message ring clean up in r212321.
- Instead of dropping Tx packet on credit fail, retry send until it
  succeeds.
- Fix freeing mbufs in case of P2P descriptors:
  We cannot free the mbuf when the P2P descriptor freeback is received. The
  mbuf may be still in use by the GMAC, since the P2P freeback indicates that
  it read the P2D descriptors in the P2P message.
  Now we free just the P2P descriptor when the P2P freeback message is
  received.  Another freeback P2D message has been added to the end of
  the packet descriptors, the mbuf will be freed only when we received
  this.

The P2P descriptor issue was reported by srgorti at netlogicmicro dot com.
This commit is contained in:
Jayachandran C. 2010-09-08 17:11:49 +00:00
parent b28fc1b5c8
commit 8f8ae306c6

View File

@ -207,7 +207,7 @@ static int prepare_fmn_message(struct nlge_softc *sc,
uint64_t fr_stid, struct nlge_tx_desc **tx_desc);
static void release_mbuf(uint64_t phy_addr);
static void release_tx_desc(struct msgrng_msg *msg);
static void release_tx_desc(vm_paddr_t phy_addr);
static int send_fmn_msg_tx(struct nlge_softc *, struct msgrng_msg *,
uint32_t n_entries);
@ -637,7 +637,7 @@ nlge_msgring_handler(int bucket, int size, int code, int stid,
struct nlna_softc *na_sc;
struct nlge_softc *sc;
struct ifnet *ifp;
uint64_t phys_addr;
vm_paddr_t phys_addr;
unsigned long addr;
uint32_t length;
int ctrl;
@ -655,14 +655,15 @@ nlge_msgring_handler(int bucket, int size, int code, int stid,
tx_error = 0;
length = (msg->msg0 >> 40) & 0x3fff;
na_sc = (struct nlna_softc *)data;
phys_addr = (uint64_t) (msg->msg0 & 0xffffffffe0ULL);
if (length == 0) {
ctrl = CTRL_REG_FREE;
phys_addr = msg->msg0 & 0xffffffffffULL;
port = (msg->msg0 >> 54) & 0x0f;
is_p2p = (msg->msg0 >> 62) & 0x1;
tx_error = (msg->msg0 >> 58) & 0xf;
} else {
ctrl = CTRL_SNGL;
phys_addr = msg->msg0 & 0xffffffffe0ULL;
length = length - BYTE_OFFSET - MAC_CRC_LEN;
port = msg->msg0 & 0x0f;
}
@ -676,11 +677,12 @@ nlge_msgring_handler(int bucket, int size, int code, int stid,
}
if (ctrl == CTRL_REG_FREE || ctrl == CTRL_JUMBO_FREE) {
if (is_p2p)
release_tx_desc(msg);
else {
release_mbuf(msg->msg0 & 0xffffffffffULL);
if (is_p2p) {
release_tx_desc(phys_addr);
} else {
release_mbuf(phys_addr);
}
ifp = sc->nlge_if;
if (ifp->if_drv_flags & IFF_DRV_OACTIVE){
ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
@ -742,7 +744,7 @@ nlge_start_locked(struct ifnet *ifp, struct nlge_softc *sc)
goto fail;
}
sent = send_fmn_msg_tx(sc, &msg, n_entries);
if (!sent) {
if (sent != 0) {
goto fail;
}
} while(1);
@ -1011,28 +1013,27 @@ static __inline__ int
nlna_send_free_desc(struct nlna_softc *sc, vm_paddr_t addr)
{
struct msgrng_msg msg;
int stid;
int code;
int i;
uint32_t msgrng_flags;
int i = 0, stid, code, ret;
stid = sc->rfrbucket;
memset(&msg, 0, sizeof(msg));
msg.msg0 = (uint64_t) addr & 0xffffffffe0ULL;
code = (sc->na_type == XLR_XGMAC) ? MSGRNG_CODE_XGMAC : MSGRNG_CODE_MAC;
for (i = 0; i < MAX_MSG_SND_ATTEMPTS; i++) {
if (message_send(1, code, stid, &msg) == 0)
return (0);
}
printf("Error: failed to send free desc to station %d\n", stid);
return (1);
do {
msgrng_flags = msgrng_access_enable();
ret = message_send_retry(1, code, stid, &msg);
msgrng_restore(msgrng_flags);
KASSERT(i++ < 100000, ("Too many credit fails\n"));
} while (ret != 0);
return (0);
}
static void
nlna_submit_rx_free_desc(struct nlna_softc *sc, uint32_t n_desc)
{
void *ptr;
unsigned long msgrng_flags;
int i;
int ret;
@ -1050,10 +1051,8 @@ nlna_submit_rx_free_desc(struct nlna_softc *sc, uint32_t n_desc)
}
/* Send the free Rx desc to the MAC */
msgrng_access_enable(msgrng_flags);
ret = nlna_send_free_desc(sc, vtophys(ptr));
msgrng_access_disable(msgrng_flags);
if (ret) /* no point trying other descriptors after
if (ret != 0) /* no point trying other descriptors after
a failure. */
break;
}
@ -1907,9 +1906,10 @@ prepare_fmn_message(struct nlge_softc *sc, struct msgrng_msg *fmn_msg,
while (len) {
if (msg_sz == (FMN_SZ - 1)) {
p2p = uma_zalloc(nl_tx_desc_zone, M_WAITOK);
if (p2p == NULL)
p2p = uma_zalloc(nl_tx_desc_zone, M_NOWAIT);
if (p2p == NULL) {
return 2;
}
/*
* As we currently use xlr_paddr_lw on a 32-bit
* OS, both the pointers are laid out in one
@ -1922,7 +1922,7 @@ prepare_fmn_message(struct nlge_softc *sc, struct msgrng_msg *fmn_msg,
((vm_offset_t) mbuf_chain);
cur_p2d = &p2p->frag[0];
is_p2p = 1;
} else if (msg_sz == (FMN_SZ - 1 + XLR_MAX_TX_FRAGS)) {
} else if (msg_sz == (FMN_SZ - 2 + XLR_MAX_TX_FRAGS)) {
uma_zfree(nl_tx_desc_zone, p2p);
return 1;
}
@ -1940,26 +1940,24 @@ prepare_fmn_message(struct nlge_softc *sc, struct msgrng_msg *fmn_msg,
}
}
if (msg_sz > 0) {
cur_p2d[-1] |= (1ULL << 63); /* set eop in most-recent p2d */
} else {
if (msg_sz == 0) {
printf("Zero-length mbuf chain ??\n");
*n_entries = msg_sz ;
return 0;
}
cur_p2d[-1] |= (1ULL << 63); /* set eop in most-recent p2d */
*cur_p2d = (1ULL << 63) | ((uint64_t)fb_stn_id << 54) |
(vm_offset_t) mbuf_chain;
*tx_desc = p2p;
if (is_p2p) {
paddr = vtophys(p2p);
fmn_msg->msg3 = (1ULL << 63) | (1ULL << 62) |
((uint64_t)fb_stn_id << 54) |
p2p_sz++;
fmn_msg->msg3 = (1ULL << 62) | ((uint64_t)fb_stn_id << 54) |
((uint64_t)(p2p_sz * 8) << 40) | paddr;
*n_entries = FMN_SZ;
} else {
/* zero-len p2d */
*cur_p2d = (1ULL << 63) | ((uint64_t)fb_stn_id << 54) |
(vm_offset_t) mbuf_chain;
*n_entries = msg_sz + 1;
}
@ -1970,15 +1968,17 @@ static int
send_fmn_msg_tx(struct nlge_softc *sc, struct msgrng_msg *msg,
uint32_t n_entries)
{
unsigned long mflags;
int ret;
uint32_t msgrng_flags;
int i = 0, ret;
mflags = 0;
msgrng_access_enable(mflags);
ret = message_send_retry(n_entries, MSGRNG_CODE_MAC, sc->tx_bucket_id,
msg);
msgrng_access_disable(mflags);
return (!ret);
do {
msgrng_flags = msgrng_access_enable();
ret = message_send_retry(n_entries, MSGRNG_CODE_MAC,
sc->tx_bucket_id, msg);
msgrng_restore(msgrng_flags);
KASSERT(i++ < 100000, ("Too many credit fails\n"));
} while (ret != 0);
return (0);
}
static void
@ -1991,25 +1991,20 @@ release_mbuf(uint64_t phy_addr)
}
static void
release_tx_desc(struct msgrng_msg *msg)
release_tx_desc(vm_paddr_t paddr)
{
vm_paddr_t paddr;
uint64_t temp;
struct nlge_tx_desc *tx_desc;
struct mbuf *m;
uint32_t sr;
uint32_t val1, val2;
paddr = msg->msg0 & 0xffffffffffULL;
paddr += (XLR_MAX_TX_FRAGS * sizeof(uint64_t));
sr = xlr_enable_kx();
temp = xlr_paddr_lw(paddr);
tx_desc = (struct nlge_tx_desc*)((intptr_t) temp);
val1 = xlr_paddr_lw(paddr);
paddr += sizeof(void *);
temp = xlr_paddr_lw(paddr);
val2 = xlr_paddr_lw(paddr);
mips_wr_status(sr);
m = (struct mbuf *)((intptr_t) temp);
m_freem(m);
tx_desc = (struct nlge_tx_desc*)(intptr_t) val1;
uma_zfree(nl_tx_desc_zone, tx_desc);
}