1*12004Sjiang.liu@intel.com /*
2*12004Sjiang.liu@intel.com * CDDL HEADER START
3*12004Sjiang.liu@intel.com *
4*12004Sjiang.liu@intel.com * The contents of this file are subject to the terms of the
5*12004Sjiang.liu@intel.com * Common Development and Distribution License (the "License").
6*12004Sjiang.liu@intel.com * You may not use this file except in compliance with the License.
7*12004Sjiang.liu@intel.com *
8*12004Sjiang.liu@intel.com * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*12004Sjiang.liu@intel.com * or http://www.opensolaris.org/os/licensing.
10*12004Sjiang.liu@intel.com * See the License for the specific language governing permissions
11*12004Sjiang.liu@intel.com * and limitations under the License.
12*12004Sjiang.liu@intel.com *
13*12004Sjiang.liu@intel.com * When distributing Covered Code, include this CDDL HEADER in each
14*12004Sjiang.liu@intel.com * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*12004Sjiang.liu@intel.com * If applicable, add the following below this CDDL HEADER, with the
16*12004Sjiang.liu@intel.com * fields enclosed by brackets "[]" replaced with your own identifying
17*12004Sjiang.liu@intel.com * information: Portions Copyright [yyyy] [name of copyright owner]
18*12004Sjiang.liu@intel.com *
19*12004Sjiang.liu@intel.com * CDDL HEADER END
20*12004Sjiang.liu@intel.com */
21*12004Sjiang.liu@intel.com
22*12004Sjiang.liu@intel.com /*
23*12004Sjiang.liu@intel.com * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24*12004Sjiang.liu@intel.com * Use is subject to license terms.
25*12004Sjiang.liu@intel.com */
26*12004Sjiang.liu@intel.com /*
27*12004Sjiang.liu@intel.com * Copyright (c) 2010, Intel Corporation.
28*12004Sjiang.liu@intel.com * All rights reserved.
29*12004Sjiang.liu@intel.com */
30*12004Sjiang.liu@intel.com
31*12004Sjiang.liu@intel.com /*
32*12004Sjiang.liu@intel.com * DR memory support routines.
33*12004Sjiang.liu@intel.com */
34*12004Sjiang.liu@intel.com
35*12004Sjiang.liu@intel.com #include <sys/note.h>
36*12004Sjiang.liu@intel.com #include <sys/debug.h>
37*12004Sjiang.liu@intel.com #include <sys/types.h>
38*12004Sjiang.liu@intel.com #include <sys/errno.h>
39*12004Sjiang.liu@intel.com #include <sys/param.h>
40*12004Sjiang.liu@intel.com #include <sys/kmem.h>
41*12004Sjiang.liu@intel.com #include <sys/kobj.h>
42*12004Sjiang.liu@intel.com #include <sys/conf.h>
43*12004Sjiang.liu@intel.com #include <sys/dditypes.h>
44*12004Sjiang.liu@intel.com #include <sys/ddi.h>
45*12004Sjiang.liu@intel.com #include <sys/sunddi.h>
46*12004Sjiang.liu@intel.com #include <sys/sunndi.h>
47*12004Sjiang.liu@intel.com #include <sys/ddi_impldefs.h>
48*12004Sjiang.liu@intel.com #include <sys/ndi_impldefs.h>
49*12004Sjiang.liu@intel.com #include <sys/sysmacros.h>
50*12004Sjiang.liu@intel.com #include <sys/machsystm.h>
51*12004Sjiang.liu@intel.com #include <sys/promif.h>
52*12004Sjiang.liu@intel.com #include <sys/lgrp.h>
53*12004Sjiang.liu@intel.com #include <sys/mem_config.h>
54*12004Sjiang.liu@intel.com #include <vm/seg_kmem.h>
55*12004Sjiang.liu@intel.com #include <vm/page.h>
56*12004Sjiang.liu@intel.com
57*12004Sjiang.liu@intel.com #include <sys/dr.h>
58*12004Sjiang.liu@intel.com #include <sys/dr_util.h>
59*12004Sjiang.liu@intel.com #include <sys/drmach.h>
60*12004Sjiang.liu@intel.com
61*12004Sjiang.liu@intel.com extern struct memlist *phys_install;
62*12004Sjiang.liu@intel.com
63*12004Sjiang.liu@intel.com /* TODO: push this reference below drmach line */
64*12004Sjiang.liu@intel.com extern int kcage_on;
65*12004Sjiang.liu@intel.com
66*12004Sjiang.liu@intel.com /* for the DR*INTERNAL_ERROR macros. see sys/dr.h. */
67*12004Sjiang.liu@intel.com static char *dr_ie_fmt = "dr_mem_acpi.c %d";
68*12004Sjiang.liu@intel.com
69*12004Sjiang.liu@intel.com static void dr_init_mem_unit_data(dr_mem_unit_t *mp);
70*12004Sjiang.liu@intel.com
71*12004Sjiang.liu@intel.com /*
72*12004Sjiang.liu@intel.com * dr_mem_unit_t.sbm_flags
73*12004Sjiang.liu@intel.com */
74*12004Sjiang.liu@intel.com #define DR_MFLAG_RESERVED 0x01 /* mem unit reserved for delete */
75*12004Sjiang.liu@intel.com #define DR_MFLAG_SOURCE 0x02 /* source brd of copy/rename op */
76*12004Sjiang.liu@intel.com #define DR_MFLAG_TARGET 0x04 /* target brd of copy/rename op */
77*12004Sjiang.liu@intel.com #define DR_MFLAG_RELOWNER 0x20 /* memory release (delete) owner */
78*12004Sjiang.liu@intel.com #define DR_MFLAG_RELDONE 0x40 /* memory release (delete) done */
79*12004Sjiang.liu@intel.com
80*12004Sjiang.liu@intel.com /* helper macros */
81*12004Sjiang.liu@intel.com #define _ptob64(p) ((uint64_t)(p) << PAGESHIFT)
82*12004Sjiang.liu@intel.com #define _b64top(b) ((pgcnt_t)((b) >> PAGESHIFT))
83*12004Sjiang.liu@intel.com
84*12004Sjiang.liu@intel.com static struct memlist *
dr_get_memlist(dr_mem_unit_t * mp)85*12004Sjiang.liu@intel.com dr_get_memlist(dr_mem_unit_t *mp)
86*12004Sjiang.liu@intel.com {
87*12004Sjiang.liu@intel.com struct memlist *mlist = NULL;
88*12004Sjiang.liu@intel.com sbd_error_t *err;
89*12004Sjiang.liu@intel.com static fn_t f = "dr_get_memlist";
90*12004Sjiang.liu@intel.com
91*12004Sjiang.liu@intel.com PR_MEM("%s for %s...\n", f, mp->sbm_cm.sbdev_path);
92*12004Sjiang.liu@intel.com
93*12004Sjiang.liu@intel.com /*
94*12004Sjiang.liu@intel.com * Return cached memlist, if present.
95*12004Sjiang.liu@intel.com * This memlist will be present following an
96*12004Sjiang.liu@intel.com * unconfigure (a.k.a: detach) of this memunit.
97*12004Sjiang.liu@intel.com * It should only be used in the case were a configure
98*12004Sjiang.liu@intel.com * is bringing this memunit back in without going
99*12004Sjiang.liu@intel.com * through the disconnect and connect states.
100*12004Sjiang.liu@intel.com */
101*12004Sjiang.liu@intel.com if (mp->sbm_mlist) {
102*12004Sjiang.liu@intel.com PR_MEM("%s: found cached memlist\n", f);
103*12004Sjiang.liu@intel.com
104*12004Sjiang.liu@intel.com mlist = memlist_dup(mp->sbm_mlist);
105*12004Sjiang.liu@intel.com } else {
106*12004Sjiang.liu@intel.com uint64_t basepa = _ptob64(mp->sbm_basepfn);
107*12004Sjiang.liu@intel.com
108*12004Sjiang.liu@intel.com /* attempt to construct a memlist using phys_install */
109*12004Sjiang.liu@intel.com
110*12004Sjiang.liu@intel.com /* round down to slice base address */
111*12004Sjiang.liu@intel.com basepa &= ~mp->sbm_alignment_mask;
112*12004Sjiang.liu@intel.com
113*12004Sjiang.liu@intel.com /* get a copy of phys_install to edit */
114*12004Sjiang.liu@intel.com memlist_read_lock();
115*12004Sjiang.liu@intel.com mlist = memlist_dup(phys_install);
116*12004Sjiang.liu@intel.com memlist_read_unlock();
117*12004Sjiang.liu@intel.com
118*12004Sjiang.liu@intel.com /* trim lower irrelevant span */
119*12004Sjiang.liu@intel.com if (mlist)
120*12004Sjiang.liu@intel.com mlist = memlist_del_span(mlist, 0ull, basepa);
121*12004Sjiang.liu@intel.com
122*12004Sjiang.liu@intel.com /* trim upper irrelevant span */
123*12004Sjiang.liu@intel.com if (mlist) {
124*12004Sjiang.liu@intel.com uint64_t endpa, toppa;
125*12004Sjiang.liu@intel.com
126*12004Sjiang.liu@intel.com toppa = mp->sbm_slice_top;
127*12004Sjiang.liu@intel.com endpa = _ptob64(physmax + 1);
128*12004Sjiang.liu@intel.com if (endpa > toppa)
129*12004Sjiang.liu@intel.com mlist = memlist_del_span(
130*12004Sjiang.liu@intel.com mlist, toppa,
131*12004Sjiang.liu@intel.com endpa - toppa);
132*12004Sjiang.liu@intel.com }
133*12004Sjiang.liu@intel.com
134*12004Sjiang.liu@intel.com if (mlist) {
135*12004Sjiang.liu@intel.com /* successfully built a memlist */
136*12004Sjiang.liu@intel.com PR_MEM("%s: derived memlist from phys_install\n", f);
137*12004Sjiang.liu@intel.com }
138*12004Sjiang.liu@intel.com
139*12004Sjiang.liu@intel.com /* if no mlist yet, try platform layer */
140*12004Sjiang.liu@intel.com if (!mlist) {
141*12004Sjiang.liu@intel.com err = drmach_mem_get_memlist(
142*12004Sjiang.liu@intel.com mp->sbm_cm.sbdev_id, &mlist);
143*12004Sjiang.liu@intel.com if (err) {
144*12004Sjiang.liu@intel.com DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err);
145*12004Sjiang.liu@intel.com mlist = NULL; /* paranoia */
146*12004Sjiang.liu@intel.com }
147*12004Sjiang.liu@intel.com }
148*12004Sjiang.liu@intel.com }
149*12004Sjiang.liu@intel.com
150*12004Sjiang.liu@intel.com PR_MEM("%s: memlist for %s\n", f, mp->sbm_cm.sbdev_path);
151*12004Sjiang.liu@intel.com PR_MEMLIST_DUMP(mlist);
152*12004Sjiang.liu@intel.com
153*12004Sjiang.liu@intel.com return (mlist);
154*12004Sjiang.liu@intel.com }
155*12004Sjiang.liu@intel.com
156*12004Sjiang.liu@intel.com /*ARGSUSED*/
157*12004Sjiang.liu@intel.com void
dr_release_mem(dr_common_unit_t * cp)158*12004Sjiang.liu@intel.com dr_release_mem(dr_common_unit_t *cp)
159*12004Sjiang.liu@intel.com {
160*12004Sjiang.liu@intel.com }
161*12004Sjiang.liu@intel.com
162*12004Sjiang.liu@intel.com void
dr_attach_mem(dr_handle_t * hp,dr_common_unit_t * cp)163*12004Sjiang.liu@intel.com dr_attach_mem(dr_handle_t *hp, dr_common_unit_t *cp)
164*12004Sjiang.liu@intel.com {
165*12004Sjiang.liu@intel.com dr_mem_unit_t *mp = (dr_mem_unit_t *)cp;
166*12004Sjiang.liu@intel.com struct memlist *ml, *mc;
167*12004Sjiang.liu@intel.com sbd_error_t *err;
168*12004Sjiang.liu@intel.com static fn_t f = "dr_attach_mem";
169*12004Sjiang.liu@intel.com uint64_t dr_physmax;
170*12004Sjiang.liu@intel.com
171*12004Sjiang.liu@intel.com PR_MEM("%s...\n", f);
172*12004Sjiang.liu@intel.com
173*12004Sjiang.liu@intel.com dr_lock_status(hp->h_bd);
174*12004Sjiang.liu@intel.com err = drmach_configure(cp->sbdev_id, 0);
175*12004Sjiang.liu@intel.com dr_unlock_status(hp->h_bd);
176*12004Sjiang.liu@intel.com if (err) {
177*12004Sjiang.liu@intel.com DRERR_SET_C(&cp->sbdev_error, &err);
178*12004Sjiang.liu@intel.com return;
179*12004Sjiang.liu@intel.com }
180*12004Sjiang.liu@intel.com
181*12004Sjiang.liu@intel.com ml = dr_get_memlist(mp);
182*12004Sjiang.liu@intel.com
183*12004Sjiang.liu@intel.com /* Skip memory with address above plat_dr_physmax or kpm_size */
184*12004Sjiang.liu@intel.com dr_physmax = plat_dr_physmax ? ptob(plat_dr_physmax) : UINT64_MAX;
185*12004Sjiang.liu@intel.com if (kpm_size < dr_physmax)
186*12004Sjiang.liu@intel.com dr_physmax = kpm_size;
187*12004Sjiang.liu@intel.com ml = memlist_del_span(ml, dr_physmax, UINT64_MAX - dr_physmax);
188*12004Sjiang.liu@intel.com
189*12004Sjiang.liu@intel.com for (mc = ml; mc; mc = mc->ml_next) {
190*12004Sjiang.liu@intel.com int rv;
191*12004Sjiang.liu@intel.com sbd_error_t *err;
192*12004Sjiang.liu@intel.com
193*12004Sjiang.liu@intel.com rv = kphysm_add_memory_dynamic(
194*12004Sjiang.liu@intel.com (pfn_t)btop(mc->ml_address),
195*12004Sjiang.liu@intel.com (pgcnt_t)btop(mc->ml_size));
196*12004Sjiang.liu@intel.com if (rv != KPHYSM_OK) {
197*12004Sjiang.liu@intel.com /*
198*12004Sjiang.liu@intel.com * translate kphysm error and
199*12004Sjiang.liu@intel.com * store in devlist error
200*12004Sjiang.liu@intel.com */
201*12004Sjiang.liu@intel.com switch (rv) {
202*12004Sjiang.liu@intel.com case KPHYSM_ERESOURCE:
203*12004Sjiang.liu@intel.com rv = ESBD_NOMEM;
204*12004Sjiang.liu@intel.com break;
205*12004Sjiang.liu@intel.com
206*12004Sjiang.liu@intel.com case KPHYSM_EFAULT:
207*12004Sjiang.liu@intel.com rv = ESBD_FAULT;
208*12004Sjiang.liu@intel.com break;
209*12004Sjiang.liu@intel.com
210*12004Sjiang.liu@intel.com default:
211*12004Sjiang.liu@intel.com rv = ESBD_INTERNAL;
212*12004Sjiang.liu@intel.com break;
213*12004Sjiang.liu@intel.com }
214*12004Sjiang.liu@intel.com
215*12004Sjiang.liu@intel.com if (rv == ESBD_INTERNAL) {
216*12004Sjiang.liu@intel.com DR_DEV_INTERNAL_ERROR(&mp->sbm_cm);
217*12004Sjiang.liu@intel.com } else
218*12004Sjiang.liu@intel.com dr_dev_err(CE_WARN, &mp->sbm_cm, rv);
219*12004Sjiang.liu@intel.com break;
220*12004Sjiang.liu@intel.com }
221*12004Sjiang.liu@intel.com
222*12004Sjiang.liu@intel.com err = drmach_mem_add_span(
223*12004Sjiang.liu@intel.com mp->sbm_cm.sbdev_id, mc->ml_address, mc->ml_size);
224*12004Sjiang.liu@intel.com if (err) {
225*12004Sjiang.liu@intel.com DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err);
226*12004Sjiang.liu@intel.com break;
227*12004Sjiang.liu@intel.com }
228*12004Sjiang.liu@intel.com }
229*12004Sjiang.liu@intel.com
230*12004Sjiang.liu@intel.com memlist_delete(ml);
231*12004Sjiang.liu@intel.com dr_init_mem_unit_data(mp);
232*12004Sjiang.liu@intel.com
233*12004Sjiang.liu@intel.com /* back out if configure failed */
234*12004Sjiang.liu@intel.com if (mp->sbm_cm.sbdev_error != NULL) {
235*12004Sjiang.liu@intel.com dr_lock_status(hp->h_bd);
236*12004Sjiang.liu@intel.com err = drmach_unconfigure(cp->sbdev_id, 0);
237*12004Sjiang.liu@intel.com if (err)
238*12004Sjiang.liu@intel.com sbd_err_clear(&err);
239*12004Sjiang.liu@intel.com dr_unlock_status(hp->h_bd);
240*12004Sjiang.liu@intel.com }
241*12004Sjiang.liu@intel.com }
242*12004Sjiang.liu@intel.com
243*12004Sjiang.liu@intel.com /*ARGSUSED*/
244*12004Sjiang.liu@intel.com void
dr_detach_mem(dr_handle_t * hp,dr_common_unit_t * cp)245*12004Sjiang.liu@intel.com dr_detach_mem(dr_handle_t *hp, dr_common_unit_t *cp)
246*12004Sjiang.liu@intel.com {
247*12004Sjiang.liu@intel.com }
248*12004Sjiang.liu@intel.com
249*12004Sjiang.liu@intel.com /*
250*12004Sjiang.liu@intel.com * This routine acts as a wrapper for kphysm_del_span_query in order to
251*12004Sjiang.liu@intel.com * support potential memory holes in a board's physical address space.
252*12004Sjiang.liu@intel.com * It calls kphysm_del_span_query for each node in a memlist and accumulates
253*12004Sjiang.liu@intel.com * the results in *mp.
254*12004Sjiang.liu@intel.com */
255*12004Sjiang.liu@intel.com static int
dr_del_mlist_query(struct memlist * mlist,memquery_t * mp)256*12004Sjiang.liu@intel.com dr_del_mlist_query(struct memlist *mlist, memquery_t *mp)
257*12004Sjiang.liu@intel.com {
258*12004Sjiang.liu@intel.com int rv = 0;
259*12004Sjiang.liu@intel.com
260*12004Sjiang.liu@intel.com if (mlist == NULL)
261*12004Sjiang.liu@intel.com cmn_err(CE_WARN, "dr_del_mlist_query: mlist=NULL\n");
262*12004Sjiang.liu@intel.com
263*12004Sjiang.liu@intel.com mp->phys_pages = 0;
264*12004Sjiang.liu@intel.com mp->managed = 0;
265*12004Sjiang.liu@intel.com mp->nonrelocatable = 0;
266*12004Sjiang.liu@intel.com mp->first_nonrelocatable = 0;
267*12004Sjiang.liu@intel.com mp->last_nonrelocatable = 0;
268*12004Sjiang.liu@intel.com
269*12004Sjiang.liu@intel.com return (rv);
270*12004Sjiang.liu@intel.com }
271*12004Sjiang.liu@intel.com
272*12004Sjiang.liu@intel.com /*
273*12004Sjiang.liu@intel.com * NOTE: This routine is only partially smart about multiple
274*12004Sjiang.liu@intel.com * mem-units. Need to make mem-status structure smart
275*12004Sjiang.liu@intel.com * about them also.
276*12004Sjiang.liu@intel.com */
277*12004Sjiang.liu@intel.com int
dr_mem_status(dr_handle_t * hp,dr_devset_t devset,sbd_dev_stat_t * dsp)278*12004Sjiang.liu@intel.com dr_mem_status(dr_handle_t *hp, dr_devset_t devset, sbd_dev_stat_t *dsp)
279*12004Sjiang.liu@intel.com {
280*12004Sjiang.liu@intel.com int m, mix;
281*12004Sjiang.liu@intel.com memquery_t mq;
282*12004Sjiang.liu@intel.com dr_board_t *bp;
283*12004Sjiang.liu@intel.com dr_mem_unit_t *mp;
284*12004Sjiang.liu@intel.com sbd_mem_stat_t *msp;
285*12004Sjiang.liu@intel.com static fn_t f = "dr_mem_status";
286*12004Sjiang.liu@intel.com
287*12004Sjiang.liu@intel.com bp = hp->h_bd;
288*12004Sjiang.liu@intel.com devset &= DR_DEVS_PRESENT(bp);
289*12004Sjiang.liu@intel.com
290*12004Sjiang.liu@intel.com for (m = mix = 0; m < MAX_MEM_UNITS_PER_BOARD; m++) {
291*12004Sjiang.liu@intel.com int rv;
292*12004Sjiang.liu@intel.com sbd_error_t *err;
293*12004Sjiang.liu@intel.com drmach_status_t pstat;
294*12004Sjiang.liu@intel.com dr_mem_unit_t *p_mp;
295*12004Sjiang.liu@intel.com
296*12004Sjiang.liu@intel.com if (DEVSET_IN_SET(devset, SBD_COMP_MEM, m) == 0)
297*12004Sjiang.liu@intel.com continue;
298*12004Sjiang.liu@intel.com
299*12004Sjiang.liu@intel.com mp = dr_get_mem_unit(bp, m);
300*12004Sjiang.liu@intel.com
301*12004Sjiang.liu@intel.com if (mp->sbm_cm.sbdev_state == DR_STATE_EMPTY) {
302*12004Sjiang.liu@intel.com /* present, but not fully initialized */
303*12004Sjiang.liu@intel.com continue;
304*12004Sjiang.liu@intel.com }
305*12004Sjiang.liu@intel.com
306*12004Sjiang.liu@intel.com if (mp->sbm_cm.sbdev_id == (drmachid_t)0)
307*12004Sjiang.liu@intel.com continue;
308*12004Sjiang.liu@intel.com
309*12004Sjiang.liu@intel.com /* fetch platform status */
310*12004Sjiang.liu@intel.com err = drmach_status(mp->sbm_cm.sbdev_id, &pstat);
311*12004Sjiang.liu@intel.com if (err) {
312*12004Sjiang.liu@intel.com DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err);
313*12004Sjiang.liu@intel.com continue;
314*12004Sjiang.liu@intel.com }
315*12004Sjiang.liu@intel.com
316*12004Sjiang.liu@intel.com msp = &dsp->d_mem;
317*12004Sjiang.liu@intel.com bzero((caddr_t)msp, sizeof (*msp));
318*12004Sjiang.liu@intel.com
319*12004Sjiang.liu@intel.com (void) strlcpy(msp->ms_cm.c_id.c_name, pstat.type,
320*12004Sjiang.liu@intel.com sizeof (msp->ms_cm.c_id.c_name));
321*12004Sjiang.liu@intel.com msp->ms_cm.c_id.c_type = mp->sbm_cm.sbdev_type;
322*12004Sjiang.liu@intel.com msp->ms_cm.c_id.c_unit = mp->sbm_cm.sbdev_unum;
323*12004Sjiang.liu@intel.com msp->ms_cm.c_cond = mp->sbm_cm.sbdev_cond;
324*12004Sjiang.liu@intel.com msp->ms_cm.c_busy = mp->sbm_cm.sbdev_busy | pstat.busy;
325*12004Sjiang.liu@intel.com msp->ms_cm.c_time = mp->sbm_cm.sbdev_time;
326*12004Sjiang.liu@intel.com msp->ms_cm.c_ostate = mp->sbm_cm.sbdev_ostate;
327*12004Sjiang.liu@intel.com
328*12004Sjiang.liu@intel.com msp->ms_totpages = mp->sbm_npages;
329*12004Sjiang.liu@intel.com msp->ms_basepfn = mp->sbm_basepfn;
330*12004Sjiang.liu@intel.com msp->ms_pageslost = mp->sbm_pageslost;
331*12004Sjiang.liu@intel.com msp->ms_cage_enabled = kcage_on;
332*12004Sjiang.liu@intel.com
333*12004Sjiang.liu@intel.com if (mp->sbm_flags & DR_MFLAG_RESERVED)
334*12004Sjiang.liu@intel.com p_mp = mp->sbm_peer;
335*12004Sjiang.liu@intel.com else
336*12004Sjiang.liu@intel.com p_mp = NULL;
337*12004Sjiang.liu@intel.com
338*12004Sjiang.liu@intel.com if (p_mp == NULL) {
339*12004Sjiang.liu@intel.com msp->ms_peer_is_target = 0;
340*12004Sjiang.liu@intel.com msp->ms_peer_ap_id[0] = '\0';
341*12004Sjiang.liu@intel.com } else if (p_mp->sbm_flags & DR_MFLAG_RESERVED) {
342*12004Sjiang.liu@intel.com char *path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
343*12004Sjiang.liu@intel.com char *minor;
344*12004Sjiang.liu@intel.com
345*12004Sjiang.liu@intel.com /*
346*12004Sjiang.liu@intel.com * b_dip doesn't have to be held for ddi_pathname()
347*12004Sjiang.liu@intel.com * because the board struct (dr_board_t) will be
348*12004Sjiang.liu@intel.com * destroyed before b_dip detaches.
349*12004Sjiang.liu@intel.com */
350*12004Sjiang.liu@intel.com (void) ddi_pathname(bp->b_dip, path);
351*12004Sjiang.liu@intel.com minor = strchr(p_mp->sbm_cm.sbdev_path, ':');
352*12004Sjiang.liu@intel.com
353*12004Sjiang.liu@intel.com (void) snprintf(msp->ms_peer_ap_id,
354*12004Sjiang.liu@intel.com sizeof (msp->ms_peer_ap_id), "%s%s",
355*12004Sjiang.liu@intel.com path, (minor == NULL) ? "" : minor);
356*12004Sjiang.liu@intel.com
357*12004Sjiang.liu@intel.com kmem_free(path, MAXPATHLEN);
358*12004Sjiang.liu@intel.com
359*12004Sjiang.liu@intel.com if (p_mp->sbm_flags & DR_MFLAG_TARGET)
360*12004Sjiang.liu@intel.com msp->ms_peer_is_target = 1;
361*12004Sjiang.liu@intel.com }
362*12004Sjiang.liu@intel.com
363*12004Sjiang.liu@intel.com /*
364*12004Sjiang.liu@intel.com * kphysm_del_span_query can report non-reloc pages = total
365*12004Sjiang.liu@intel.com * pages for memory that is not yet configured
366*12004Sjiang.liu@intel.com */
367*12004Sjiang.liu@intel.com if (mp->sbm_cm.sbdev_state != DR_STATE_UNCONFIGURED) {
368*12004Sjiang.liu@intel.com struct memlist *ml;
369*12004Sjiang.liu@intel.com
370*12004Sjiang.liu@intel.com ml = dr_get_memlist(mp);
371*12004Sjiang.liu@intel.com rv = ml ? dr_del_mlist_query(ml, &mq) : -1;
372*12004Sjiang.liu@intel.com memlist_delete(ml);
373*12004Sjiang.liu@intel.com
374*12004Sjiang.liu@intel.com if (rv == KPHYSM_OK) {
375*12004Sjiang.liu@intel.com msp->ms_managed_pages = mq.managed;
376*12004Sjiang.liu@intel.com msp->ms_noreloc_pages = mq.nonrelocatable;
377*12004Sjiang.liu@intel.com msp->ms_noreloc_first =
378*12004Sjiang.liu@intel.com mq.first_nonrelocatable;
379*12004Sjiang.liu@intel.com msp->ms_noreloc_last =
380*12004Sjiang.liu@intel.com mq.last_nonrelocatable;
381*12004Sjiang.liu@intel.com msp->ms_cm.c_sflags = 0;
382*12004Sjiang.liu@intel.com if (mq.nonrelocatable &&
383*12004Sjiang.liu@intel.com drmach_copy_rename_need_suspend(
384*12004Sjiang.liu@intel.com mp->sbm_cm.sbdev_id)) {
385*12004Sjiang.liu@intel.com SBD_SET_SUSPEND(SBD_CMD_UNCONFIGURE,
386*12004Sjiang.liu@intel.com msp->ms_cm.c_sflags);
387*12004Sjiang.liu@intel.com }
388*12004Sjiang.liu@intel.com } else {
389*12004Sjiang.liu@intel.com PR_MEM("%s: kphysm_del_span_query() = %d\n",
390*12004Sjiang.liu@intel.com f, rv);
391*12004Sjiang.liu@intel.com }
392*12004Sjiang.liu@intel.com }
393*12004Sjiang.liu@intel.com
394*12004Sjiang.liu@intel.com /*
395*12004Sjiang.liu@intel.com * Check source unit state during copy-rename
396*12004Sjiang.liu@intel.com */
397*12004Sjiang.liu@intel.com if ((mp->sbm_flags & DR_MFLAG_SOURCE) &&
398*12004Sjiang.liu@intel.com (mp->sbm_cm.sbdev_state == DR_STATE_UNREFERENCED ||
399*12004Sjiang.liu@intel.com mp->sbm_cm.sbdev_state == DR_STATE_RELEASE))
400*12004Sjiang.liu@intel.com msp->ms_cm.c_ostate = SBD_STAT_CONFIGURED;
401*12004Sjiang.liu@intel.com
402*12004Sjiang.liu@intel.com mix++;
403*12004Sjiang.liu@intel.com dsp++;
404*12004Sjiang.liu@intel.com }
405*12004Sjiang.liu@intel.com
406*12004Sjiang.liu@intel.com return (mix);
407*12004Sjiang.liu@intel.com }
408*12004Sjiang.liu@intel.com
409*12004Sjiang.liu@intel.com /*ARGSUSED*/
410*12004Sjiang.liu@intel.com int
dr_pre_attach_mem(dr_handle_t * hp,dr_common_unit_t ** devlist,int devnum)411*12004Sjiang.liu@intel.com dr_pre_attach_mem(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
412*12004Sjiang.liu@intel.com {
413*12004Sjiang.liu@intel.com int err_flag = 0;
414*12004Sjiang.liu@intel.com int d;
415*12004Sjiang.liu@intel.com sbd_error_t *err;
416*12004Sjiang.liu@intel.com static fn_t f = "dr_pre_attach_mem";
417*12004Sjiang.liu@intel.com
418*12004Sjiang.liu@intel.com PR_MEM("%s...\n", f);
419*12004Sjiang.liu@intel.com
420*12004Sjiang.liu@intel.com for (d = 0; d < devnum; d++) {
421*12004Sjiang.liu@intel.com dr_mem_unit_t *mp = (dr_mem_unit_t *)devlist[d];
422*12004Sjiang.liu@intel.com dr_state_t state;
423*12004Sjiang.liu@intel.com
424*12004Sjiang.liu@intel.com cmn_err(CE_CONT, "OS configure %s", mp->sbm_cm.sbdev_path);
425*12004Sjiang.liu@intel.com
426*12004Sjiang.liu@intel.com state = mp->sbm_cm.sbdev_state;
427*12004Sjiang.liu@intel.com switch (state) {
428*12004Sjiang.liu@intel.com case DR_STATE_UNCONFIGURED:
429*12004Sjiang.liu@intel.com PR_MEM("%s: recovering from UNCONFIG for %s\n",
430*12004Sjiang.liu@intel.com f, mp->sbm_cm.sbdev_path);
431*12004Sjiang.liu@intel.com
432*12004Sjiang.liu@intel.com /* use memlist cached by dr_post_detach_mem_unit */
433*12004Sjiang.liu@intel.com ASSERT(mp->sbm_mlist != NULL);
434*12004Sjiang.liu@intel.com PR_MEM("%s: re-configuring cached memlist for %s:\n",
435*12004Sjiang.liu@intel.com f, mp->sbm_cm.sbdev_path);
436*12004Sjiang.liu@intel.com PR_MEMLIST_DUMP(mp->sbm_mlist);
437*12004Sjiang.liu@intel.com
438*12004Sjiang.liu@intel.com /* kphysm del handle should be have been freed */
439*12004Sjiang.liu@intel.com ASSERT((mp->sbm_flags & DR_MFLAG_RELOWNER) == 0);
440*12004Sjiang.liu@intel.com
441*12004Sjiang.liu@intel.com /*FALLTHROUGH*/
442*12004Sjiang.liu@intel.com
443*12004Sjiang.liu@intel.com case DR_STATE_CONNECTED:
444*12004Sjiang.liu@intel.com PR_MEM("%s: reprogramming mem hardware on %s\n",
445*12004Sjiang.liu@intel.com f, mp->sbm_cm.sbdev_bp->b_path);
446*12004Sjiang.liu@intel.com
447*12004Sjiang.liu@intel.com PR_MEM("%s: enabling %s\n",
448*12004Sjiang.liu@intel.com f, mp->sbm_cm.sbdev_path);
449*12004Sjiang.liu@intel.com
450*12004Sjiang.liu@intel.com err = drmach_mem_enable(mp->sbm_cm.sbdev_id);
451*12004Sjiang.liu@intel.com if (err) {
452*12004Sjiang.liu@intel.com DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err);
453*12004Sjiang.liu@intel.com err_flag = 1;
454*12004Sjiang.liu@intel.com }
455*12004Sjiang.liu@intel.com break;
456*12004Sjiang.liu@intel.com
457*12004Sjiang.liu@intel.com default:
458*12004Sjiang.liu@intel.com dr_dev_err(CE_WARN, &mp->sbm_cm, ESBD_STATE);
459*12004Sjiang.liu@intel.com err_flag = 1;
460*12004Sjiang.liu@intel.com break;
461*12004Sjiang.liu@intel.com }
462*12004Sjiang.liu@intel.com
463*12004Sjiang.liu@intel.com /* exit for loop if error encountered */
464*12004Sjiang.liu@intel.com if (err_flag)
465*12004Sjiang.liu@intel.com break;
466*12004Sjiang.liu@intel.com }
467*12004Sjiang.liu@intel.com
468*12004Sjiang.liu@intel.com return (err_flag ? -1 : 0);
469*12004Sjiang.liu@intel.com }
470*12004Sjiang.liu@intel.com
471*12004Sjiang.liu@intel.com /*ARGSUSED*/
472*12004Sjiang.liu@intel.com int
dr_post_attach_mem(dr_handle_t * hp,dr_common_unit_t ** devlist,int devnum)473*12004Sjiang.liu@intel.com dr_post_attach_mem(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
474*12004Sjiang.liu@intel.com {
475*12004Sjiang.liu@intel.com int d;
476*12004Sjiang.liu@intel.com static fn_t f = "dr_post_attach_mem";
477*12004Sjiang.liu@intel.com
478*12004Sjiang.liu@intel.com PR_MEM("%s...\n", f);
479*12004Sjiang.liu@intel.com
480*12004Sjiang.liu@intel.com for (d = 0; d < devnum; d++) {
481*12004Sjiang.liu@intel.com dr_mem_unit_t *mp = (dr_mem_unit_t *)devlist[d];
482*12004Sjiang.liu@intel.com struct memlist *mlist, *ml;
483*12004Sjiang.liu@intel.com
484*12004Sjiang.liu@intel.com mlist = dr_get_memlist(mp);
485*12004Sjiang.liu@intel.com
486*12004Sjiang.liu@intel.com /*
487*12004Sjiang.liu@intel.com * Verify the memory really did successfully attach
488*12004Sjiang.liu@intel.com * by checking for its existence in phys_install.
489*12004Sjiang.liu@intel.com */
490*12004Sjiang.liu@intel.com memlist_read_lock();
491*12004Sjiang.liu@intel.com if (memlist_intersect(phys_install, mlist) == 0) {
492*12004Sjiang.liu@intel.com memlist_read_unlock();
493*12004Sjiang.liu@intel.com
494*12004Sjiang.liu@intel.com DR_DEV_INTERNAL_ERROR(&mp->sbm_cm);
495*12004Sjiang.liu@intel.com
496*12004Sjiang.liu@intel.com PR_MEM("%s: %s memlist not in phys_install",
497*12004Sjiang.liu@intel.com f, mp->sbm_cm.sbdev_path);
498*12004Sjiang.liu@intel.com
499*12004Sjiang.liu@intel.com memlist_delete(mlist);
500*12004Sjiang.liu@intel.com continue;
501*12004Sjiang.liu@intel.com }
502*12004Sjiang.liu@intel.com memlist_read_unlock();
503*12004Sjiang.liu@intel.com
504*12004Sjiang.liu@intel.com for (ml = mlist; ml != NULL; ml = ml->ml_next) {
505*12004Sjiang.liu@intel.com sbd_error_t *err;
506*12004Sjiang.liu@intel.com
507*12004Sjiang.liu@intel.com err = drmach_mem_add_span(
508*12004Sjiang.liu@intel.com mp->sbm_cm.sbdev_id,
509*12004Sjiang.liu@intel.com ml->ml_address,
510*12004Sjiang.liu@intel.com ml->ml_size);
511*12004Sjiang.liu@intel.com if (err)
512*12004Sjiang.liu@intel.com DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err);
513*12004Sjiang.liu@intel.com }
514*12004Sjiang.liu@intel.com
515*12004Sjiang.liu@intel.com memlist_delete(mlist);
516*12004Sjiang.liu@intel.com
517*12004Sjiang.liu@intel.com /*
518*12004Sjiang.liu@intel.com * Destroy cached memlist, if any.
519*12004Sjiang.liu@intel.com * There will be a cached memlist in sbm_mlist if
520*12004Sjiang.liu@intel.com * this board is being configured directly after
521*12004Sjiang.liu@intel.com * an unconfigure.
522*12004Sjiang.liu@intel.com * To support this transition, dr_post_detach_mem
523*12004Sjiang.liu@intel.com * left a copy of the last known memlist in sbm_mlist.
524*12004Sjiang.liu@intel.com * This memlist could differ from any derived from
525*12004Sjiang.liu@intel.com * hardware if while this memunit was last configured
526*12004Sjiang.liu@intel.com * the system detected and deleted bad pages from
527*12004Sjiang.liu@intel.com * phys_install. The location of those bad pages
528*12004Sjiang.liu@intel.com * will be reflected in the cached memlist.
529*12004Sjiang.liu@intel.com */
530*12004Sjiang.liu@intel.com if (mp->sbm_mlist) {
531*12004Sjiang.liu@intel.com memlist_delete(mp->sbm_mlist);
532*12004Sjiang.liu@intel.com mp->sbm_mlist = NULL;
533*12004Sjiang.liu@intel.com }
534*12004Sjiang.liu@intel.com }
535*12004Sjiang.liu@intel.com
536*12004Sjiang.liu@intel.com return (0);
537*12004Sjiang.liu@intel.com }
538*12004Sjiang.liu@intel.com
539*12004Sjiang.liu@intel.com /*ARGSUSED*/
540*12004Sjiang.liu@intel.com int
dr_pre_detach_mem(dr_handle_t * hp,dr_common_unit_t ** devlist,int devnum)541*12004Sjiang.liu@intel.com dr_pre_detach_mem(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
542*12004Sjiang.liu@intel.com {
543*12004Sjiang.liu@intel.com return (-1);
544*12004Sjiang.liu@intel.com }
545*12004Sjiang.liu@intel.com
546*12004Sjiang.liu@intel.com /*ARGSUSED*/
547*12004Sjiang.liu@intel.com int
dr_post_detach_mem(dr_handle_t * hp,dr_common_unit_t ** devlist,int devnum)548*12004Sjiang.liu@intel.com dr_post_detach_mem(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
549*12004Sjiang.liu@intel.com {
550*12004Sjiang.liu@intel.com return (-1);
551*12004Sjiang.liu@intel.com }
552*12004Sjiang.liu@intel.com
553*12004Sjiang.liu@intel.com /*
554*12004Sjiang.liu@intel.com * Successful return from this function will have the memory
555*12004Sjiang.liu@intel.com * handle in bp->b_dev[..mem-unit...].sbm_memhandle allocated
556*12004Sjiang.liu@intel.com * and waiting. This routine's job is to select the memory that
557*12004Sjiang.liu@intel.com * actually has to be released (detached) which may not necessarily
558*12004Sjiang.liu@intel.com * be the same memory node that came in in devlist[],
559*12004Sjiang.liu@intel.com * i.e. a copy-rename is needed.
560*12004Sjiang.liu@intel.com */
561*12004Sjiang.liu@intel.com /*ARGSUSED*/
562*12004Sjiang.liu@intel.com int
dr_pre_release_mem(dr_handle_t * hp,dr_common_unit_t ** devlist,int devnum)563*12004Sjiang.liu@intel.com dr_pre_release_mem(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
564*12004Sjiang.liu@intel.com {
565*12004Sjiang.liu@intel.com return (-1);
566*12004Sjiang.liu@intel.com }
567*12004Sjiang.liu@intel.com
568*12004Sjiang.liu@intel.com /*ARGSUSED*/
569*12004Sjiang.liu@intel.com void
dr_release_mem_done(dr_common_unit_t * cp)570*12004Sjiang.liu@intel.com dr_release_mem_done(dr_common_unit_t *cp)
571*12004Sjiang.liu@intel.com {
572*12004Sjiang.liu@intel.com }
573*12004Sjiang.liu@intel.com
574*12004Sjiang.liu@intel.com /*ARGSUSED*/
575*12004Sjiang.liu@intel.com int
dr_disconnect_mem(dr_mem_unit_t * mp)576*12004Sjiang.liu@intel.com dr_disconnect_mem(dr_mem_unit_t *mp)
577*12004Sjiang.liu@intel.com {
578*12004Sjiang.liu@intel.com return (-1);
579*12004Sjiang.liu@intel.com }
580*12004Sjiang.liu@intel.com
581*12004Sjiang.liu@intel.com /*ARGSUSED*/
582*12004Sjiang.liu@intel.com int
dr_cancel_mem(dr_mem_unit_t * s_mp)583*12004Sjiang.liu@intel.com dr_cancel_mem(dr_mem_unit_t *s_mp)
584*12004Sjiang.liu@intel.com {
585*12004Sjiang.liu@intel.com return (-1);
586*12004Sjiang.liu@intel.com }
587*12004Sjiang.liu@intel.com
588*12004Sjiang.liu@intel.com void
dr_init_mem_unit(dr_mem_unit_t * mp)589*12004Sjiang.liu@intel.com dr_init_mem_unit(dr_mem_unit_t *mp)
590*12004Sjiang.liu@intel.com {
591*12004Sjiang.liu@intel.com dr_state_t new_state;
592*12004Sjiang.liu@intel.com
593*12004Sjiang.liu@intel.com if (DR_DEV_IS_ATTACHED(&mp->sbm_cm)) {
594*12004Sjiang.liu@intel.com new_state = DR_STATE_CONFIGURED;
595*12004Sjiang.liu@intel.com mp->sbm_cm.sbdev_cond = SBD_COND_OK;
596*12004Sjiang.liu@intel.com } else if (DR_DEV_IS_PRESENT(&mp->sbm_cm)) {
597*12004Sjiang.liu@intel.com new_state = DR_STATE_CONNECTED;
598*12004Sjiang.liu@intel.com mp->sbm_cm.sbdev_cond = SBD_COND_OK;
599*12004Sjiang.liu@intel.com } else if (mp->sbm_cm.sbdev_id != (drmachid_t)0) {
600*12004Sjiang.liu@intel.com new_state = DR_STATE_OCCUPIED;
601*12004Sjiang.liu@intel.com } else {
602*12004Sjiang.liu@intel.com new_state = DR_STATE_EMPTY;
603*12004Sjiang.liu@intel.com }
604*12004Sjiang.liu@intel.com
605*12004Sjiang.liu@intel.com if (DR_DEV_IS_PRESENT(&mp->sbm_cm))
606*12004Sjiang.liu@intel.com dr_init_mem_unit_data(mp);
607*12004Sjiang.liu@intel.com
608*12004Sjiang.liu@intel.com /* delay transition until fully initialized */
609*12004Sjiang.liu@intel.com dr_device_transition(&mp->sbm_cm, new_state);
610*12004Sjiang.liu@intel.com }
611*12004Sjiang.liu@intel.com
612*12004Sjiang.liu@intel.com static void
dr_init_mem_unit_data(dr_mem_unit_t * mp)613*12004Sjiang.liu@intel.com dr_init_mem_unit_data(dr_mem_unit_t *mp)
614*12004Sjiang.liu@intel.com {
615*12004Sjiang.liu@intel.com drmachid_t id = mp->sbm_cm.sbdev_id;
616*12004Sjiang.liu@intel.com drmach_mem_info_t minfo;
617*12004Sjiang.liu@intel.com sbd_error_t *err;
618*12004Sjiang.liu@intel.com static fn_t f = "dr_init_mem_unit_data";
619*12004Sjiang.liu@intel.com
620*12004Sjiang.liu@intel.com PR_MEM("%s...\n", f);
621*12004Sjiang.liu@intel.com
622*12004Sjiang.liu@intel.com /* a little sanity checking */
623*12004Sjiang.liu@intel.com ASSERT(mp->sbm_peer == NULL);
624*12004Sjiang.liu@intel.com ASSERT(mp->sbm_flags == 0);
625*12004Sjiang.liu@intel.com
626*12004Sjiang.liu@intel.com if (err = drmach_mem_get_info(id, &minfo)) {
627*12004Sjiang.liu@intel.com DRERR_SET_C(&mp->sbm_cm.sbdev_error, &err);
628*12004Sjiang.liu@intel.com return;
629*12004Sjiang.liu@intel.com }
630*12004Sjiang.liu@intel.com mp->sbm_basepfn = _b64top(minfo.mi_basepa);
631*12004Sjiang.liu@intel.com mp->sbm_npages = _b64top(minfo.mi_size);
632*12004Sjiang.liu@intel.com mp->sbm_alignment_mask = minfo.mi_alignment_mask;
633*12004Sjiang.liu@intel.com mp->sbm_slice_base = minfo.mi_slice_base;
634*12004Sjiang.liu@intel.com mp->sbm_slice_top = minfo.mi_slice_top;
635*12004Sjiang.liu@intel.com mp->sbm_slice_size = minfo.mi_slice_size;
636*12004Sjiang.liu@intel.com
637*12004Sjiang.liu@intel.com PR_MEM("%s: %s (basepfn = 0x%lx, npgs = %ld)\n",
638*12004Sjiang.liu@intel.com f, mp->sbm_cm.sbdev_path, mp->sbm_basepfn, mp->sbm_npages);
639*12004Sjiang.liu@intel.com }
640