Skip to content

Commit ea6b684

Browse files
author
yy150190
committed
6594676 e1000g should free private dips while no rx buffers are held by upper layer
1 parent 0dd9ed3 commit ea6b684

File tree

4 files changed

+176
-28
lines changed

4 files changed

+176
-28
lines changed

usr/src/uts/common/io/e1000g/README

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,3 +528,8 @@ Notes on packaging:
528528
6572330 e1000g: integrate the latest Intel refactored shared code
529529
6573381 e1000g receiving VLAN tagged frames does not do hardware checksumming
530530

531+
5.2.1
532+
======
533+
This version has the following fix:
534+
6594676 e1000g should free private dips while no rx buffers are held by upper layer
535+

usr/src/uts/common/io/e1000g/e1000g_main.c

Lines changed: 101 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@
4949
#define E1000_RX_INTPT_TIME 128
5050
#define E1000_RX_PKT_CNT 8
5151

52-
static char ident[] = "Intel PRO/1000 Ethernet 5.2.0";
52+
static char ident[] = "Intel PRO/1000 Ethernet 5.2.1";
5353
static char e1000g_string[] = "Intel(R) PRO/1000 Network Connection";
54-
static char e1000g_version[] = "Driver Ver. 5.2.0";
54+
static char e1000g_version[] = "Driver Ver. 5.2.1";
5555

5656
/*
5757
* Proto types for DDI entry points
@@ -142,6 +142,7 @@ static boolean_t e1000g_link_up(struct e1000g *);
142142
#ifdef __sparc
143143
static boolean_t e1000g_find_mac_address(struct e1000g *);
144144
#endif
145+
static void e1000g_free_priv_devi_node(struct e1000g *, boolean_t);
145146

146147
static struct cb_ops cb_ws_ops = {
147148
nulldev, /* cb_open */
@@ -214,6 +215,7 @@ static mac_callbacks_t e1000g_m_callbacks = {
214215
/*
215216
* Global variables
216217
*/
218+
217219
uint32_t e1000g_mblks_pending = 0;
218220
/*
219221
* Workaround for Dynamic Reconfiguration support, for x86 platform only.
@@ -393,25 +395,6 @@ e1000g_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
393395

394396
ddi_set_driver_private(devinfo, (caddr_t)Adapter);
395397

396-
if (e1000g_force_detach) {
397-
private_devi_list_t *devi_node;
398-
399-
Adapter->priv_dip =
400-
kmem_zalloc(sizeof (struct dev_info), KM_SLEEP);
401-
bcopy(DEVI(devinfo), DEVI(Adapter->priv_dip),
402-
sizeof (struct dev_info));
403-
404-
devi_node =
405-
kmem_zalloc(sizeof (private_devi_list_t), KM_SLEEP);
406-
407-
rw_enter(&e1000g_rx_detach_lock, RW_WRITER);
408-
devi_node->dip = devinfo;
409-
devi_node->priv_dip = Adapter->priv_dip;
410-
devi_node->next = e1000g_private_devi_list;
411-
e1000g_private_devi_list = devi_node;
412-
rw_exit(&e1000g_rx_detach_lock);
413-
}
414-
415398
/*
416399
* PCI Configure
417400
*/
@@ -519,6 +502,30 @@ e1000g_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
519502
}
520503
Adapter->attach_progress |= ATTACH_PROGRESS_ENABLE_INTR;
521504

505+
/*
506+
* If e1000g_force_detach is enabled, in global private dip list,
507+
* we will create a new entry, which maintains the priv_dip for DR
508+
* supports after driver detached.
509+
*/
510+
if (e1000g_force_detach) {
511+
private_devi_list_t *devi_node;
512+
513+
Adapter->priv_dip =
514+
kmem_zalloc(sizeof (struct dev_info), KM_SLEEP);
515+
bcopy(DEVI(devinfo), DEVI(Adapter->priv_dip),
516+
sizeof (struct dev_info));
517+
518+
devi_node =
519+
kmem_zalloc(sizeof (private_devi_list_t), KM_SLEEP);
520+
521+
rw_enter(&e1000g_rx_detach_lock, RW_WRITER);
522+
devi_node->priv_dip = Adapter->priv_dip;
523+
devi_node->flag = E1000G_PRIV_DEVI_ATTACH;
524+
devi_node->next = e1000g_private_devi_list;
525+
e1000g_private_devi_list = devi_node;
526+
rw_exit(&e1000g_rx_detach_lock);
527+
}
528+
522529
cmn_err(CE_CONT, "!%s, %s\n", e1000g_string, e1000g_version);
523530

524531
return (DDI_SUCCESS);
@@ -840,6 +847,7 @@ static int
840847
e1000g_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
841848
{
842849
struct e1000g *Adapter;
850+
boolean_t rx_drain;
843851

844852
switch (cmd) {
845853
default:
@@ -865,8 +873,18 @@ e1000g_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
865873
if (Adapter->started)
866874
e1000g_stop(Adapter, B_TRUE);
867875

868-
if (!e1000g_rx_drain(Adapter)) {
869-
if (!e1000g_force_detach)
876+
rx_drain = e1000g_rx_drain(Adapter);
877+
878+
/*
879+
* If e1000g_force_detach is enabled, driver detach is safe.
880+
* We will let e1000g_free_priv_devi_node routine determine
881+
* whether we need to free the priv_dip entry for current
882+
* driver instance.
883+
*/
884+
if (e1000g_force_detach) {
885+
e1000g_free_priv_devi_node(Adapter, rx_drain);
886+
} else {
887+
if (!rx_drain)
870888
return (DDI_FAILURE);
871889
}
872890

@@ -875,6 +893,66 @@ e1000g_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
875893
return (DDI_SUCCESS);
876894
}
877895

896+
/*
897+
* e1000g_free_priv_devi_node - free a priv_dip entry for driver instance
898+
*
899+
* If free_flag is true, that indicates the upper layer is not holding
900+
* the rx buffers, we could free the priv_dip entry safely.
901+
*
902+
* Otherwise, we have to keep this entry even after driver detached,
903+
* and we also need to mark this entry with E1000G_PRIV_DEVI_DETACH flag,
904+
* so that driver could free it while all of rx buffers are returned
905+
* by upper layer later.
906+
*/
907+
static void
908+
e1000g_free_priv_devi_node(struct e1000g *Adapter, boolean_t free_flag)
909+
{
910+
private_devi_list_t *devi_node, *devi_del;
911+
912+
rw_enter(&e1000g_rx_detach_lock, RW_WRITER);
913+
ASSERT(e1000g_private_devi_list != NULL);
914+
ASSERT(Adapter->priv_dip != NULL);
915+
916+
devi_node = e1000g_private_devi_list;
917+
if (devi_node->priv_dip == Adapter->priv_dip) {
918+
if (free_flag) {
919+
e1000g_private_devi_list =
920+
devi_node->next;
921+
kmem_free(devi_node->priv_dip,
922+
sizeof (struct dev_info));
923+
kmem_free(devi_node,
924+
sizeof (private_devi_list_t));
925+
} else {
926+
ASSERT(e1000g_mblks_pending != 0);
927+
devi_node->flag =
928+
E1000G_PRIV_DEVI_DETACH;
929+
}
930+
rw_exit(&e1000g_rx_detach_lock);
931+
return;
932+
}
933+
934+
devi_node = e1000g_private_devi_list;
935+
while (devi_node->next != NULL) {
936+
if (devi_node->next->priv_dip == Adapter->priv_dip) {
937+
if (free_flag) {
938+
devi_del = devi_node->next;
939+
devi_node->next = devi_del->next;
940+
kmem_free(devi_del->priv_dip,
941+
sizeof (struct dev_info));
942+
kmem_free(devi_del,
943+
sizeof (private_devi_list_t));
944+
} else {
945+
ASSERT(e1000g_mblks_pending != 0);
946+
devi_node->next->flag =
947+
E1000G_PRIV_DEVI_DETACH;
948+
}
949+
break;
950+
}
951+
devi_node = devi_node->next;
952+
}
953+
rw_exit(&e1000g_rx_detach_lock);
954+
}
955+
878956
static void
879957
e1000g_unattach(dev_info_t *devinfo, struct e1000g *Adapter)
880958
{

usr/src/uts/common/io/e1000g/e1000g_rx.c

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646

4747
static p_rx_sw_packet_t e1000g_get_buf(e1000g_rx_ring_t *rx_ring);
4848
#pragma inline(e1000g_get_buf)
49+
static void e1000g_priv_devi_list_clean();
4950

5051
/*
5152
* e1000g_rxfree_func - the call-back function to reclaim rx buffer
@@ -93,6 +94,14 @@ e1000g_rxfree_func(p_rx_sw_packet_t packet)
9394
e1000g_free_rx_sw_packet(packet);
9495
}
9596
}
97+
98+
/*
99+
* If e1000g_force_detach is enabled, we need to clean up
100+
* the idle priv_dip entries in the private dip list while
101+
* e1000g_mblks_pending is zero.
102+
*/
103+
if (e1000g_force_detach && (e1000g_mblks_pending == 0))
104+
e1000g_priv_devi_list_clean();
96105
rw_exit(&e1000g_rx_detach_lock);
97106
return;
98107
}
@@ -111,6 +120,14 @@ e1000g_rxfree_func(p_rx_sw_packet_t packet)
111120
*/
112121
rw_enter(&e1000g_rx_detach_lock, RW_WRITER);
113122
e1000g_mblks_pending--;
123+
124+
/*
125+
* If e1000g_force_detach is enabled, we need to clean up
126+
* the idle priv_dip entries in the private dip list while
127+
* e1000g_mblks_pending is zero.
128+
*/
129+
if (e1000g_force_detach && (e1000g_mblks_pending == 0))
130+
e1000g_priv_devi_list_clean();
114131
rw_exit(&e1000g_rx_detach_lock);
115132
return;
116133
}
@@ -142,6 +159,46 @@ e1000g_rxfree_func(p_rx_sw_packet_t packet)
142159
rw_exit(&e1000g_rx_detach_lock);
143160
}
144161

162+
/*
163+
* e1000g_priv_devi_list_clean - clean up e1000g_private_devi_list
164+
*
165+
* We will walk the e1000g_private_devi_list to free the entry marked
166+
* with the E1000G_PRIV_DEVI_DETACH flag.
167+
*/
168+
static void
169+
e1000g_priv_devi_list_clean()
170+
{
171+
private_devi_list_t *devi_node, *devi_del;
172+
173+
if (e1000g_private_devi_list == NULL)
174+
return;
175+
176+
devi_node = e1000g_private_devi_list;
177+
while ((devi_node != NULL) &&
178+
(devi_node->flag == E1000G_PRIV_DEVI_DETACH)) {
179+
e1000g_private_devi_list = devi_node->next;
180+
kmem_free(devi_node->priv_dip,
181+
sizeof (struct dev_info));
182+
kmem_free(devi_node,
183+
sizeof (private_devi_list_t));
184+
devi_node = e1000g_private_devi_list;
185+
}
186+
if (e1000g_private_devi_list == NULL)
187+
return;
188+
while (devi_node->next != NULL) {
189+
if (devi_node->next->flag == E1000G_PRIV_DEVI_DETACH) {
190+
devi_del = devi_node->next;
191+
devi_node->next = devi_del->next;
192+
kmem_free(devi_del->priv_dip,
193+
sizeof (struct dev_info));
194+
kmem_free(devi_del,
195+
sizeof (private_devi_list_t));
196+
} else {
197+
devi_node = devi_node->next;
198+
}
199+
}
200+
}
201+
145202
/*
146203
* e1000g_rx_setup - setup rx data structures
147204
*
@@ -550,7 +607,7 @@ e1000g_receive(struct e1000g *Adapter)
550607
*/
551608
nmp = packet->mp;
552609
packet->mp = NULL;
553-
packet->flag == E1000G_RX_SW_SENDUP;
610+
packet->flag = E1000G_RX_SW_SENDUP;
554611

555612
/*
556613
* Now replace old buffer with the new

usr/src/uts/common/io/e1000g/e1000g_sw.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,11 @@ extern "C" {
257257
#define E1000G_LB_EXTERNAL_10 3
258258
#define E1000G_LB_INTERNAL_PHY 4
259259

260+
/*
261+
* Private dip list definitions
262+
*/
263+
#define E1000G_PRIV_DEVI_ATTACH 0x0
264+
#define E1000G_PRIV_DEVI_DETACH 0x1
260265

261266
/*
262267
* QUEUE_INIT_LIST -- Macro which will init ialize a queue to NULL.
@@ -499,9 +504,12 @@ enum {
499504
PARAM_COUNT
500505
};
501506

507+
/*
508+
* The entry of the private dip list
509+
*/
502510
typedef struct _private_devi_list {
503-
dev_info_t *dip;
504511
dev_info_t *priv_dip;
512+
uint16_t flag;
505513
struct _private_devi_list *next;
506514
} private_devi_list_t;
507515

@@ -576,10 +584,10 @@ typedef struct _tx_sw_packet {
576584
* This structure is maintained as a linked list of many
577585
* receiver buffer pointers.
578586
*/
579-
typedef struct _rx_sw_apcket {
587+
typedef struct _rx_sw_packet {
580588
/* Link to the next rx_sw_packet_t in the list */
581589
SINGLE_LIST_LINK Link;
582-
struct _rx_sw_apcket *next;
590+
struct _rx_sw_packet *next;
583591
uint16_t flag;
584592
mblk_t *mp;
585593
caddr_t rx_ring;
@@ -974,7 +982,7 @@ void e1000_enable_pciex_master(struct e1000_hw *hw);
974982
extern boolean_t e1000g_force_detach;
975983
extern uint32_t e1000g_mblks_pending;
976984
extern krwlock_t e1000g_rx_detach_lock;
977-
985+
extern private_devi_list_t *e1000g_private_devi_list;
978986

979987
#ifdef __cplusplus
980988
}

0 commit comments

Comments
 (0)