diff options
Diffstat (limited to 'sys/dev')
82 files changed, 7417 insertions, 5363 deletions
diff --git a/sys/dev/acpi_support/acpi_panasonic.c b/sys/dev/acpi_support/acpi_panasonic.c index 8fea47ee45e8..5f54ca07c5a6 100644 --- a/sys/dev/acpi_support/acpi_panasonic.c +++ b/sys/dev/acpi_support/acpi_panasonic.c @@ -233,7 +233,9 @@ acpi_panasonic_shutdown(device_t dev) /* Mute the main audio during reboot to prevent static burst to speaker. */ sc = device_get_softc(dev); mute = 1; + ACPI_SERIAL_BEGIN(panasonic); hkey_sound_mute(sc->handle, HKEY_SET, &mute); + ACPI_SERIAL_END(panasonic); return (0); } diff --git a/sys/dev/amdsmu/amdsmu.c b/sys/dev/amdsmu/amdsmu.c index 7b97888887c5..5029336af9cb 100644 --- a/sys/dev/amdsmu/amdsmu.c +++ b/sys/dev/amdsmu/amdsmu.c @@ -30,11 +30,21 @@ amdsmu_match(device_t dev, const struct amdsmu_product **product_out) const uint16_t vendorid = pci_get_vendor(dev); const uint16_t deviceid = pci_get_device(dev); + const uint32_t model = CPUID_TO_MODEL(cpu_id); + for (size_t i = 0; i < nitems(amdsmu_products); i++) { const struct amdsmu_product *prod = &amdsmu_products[i]; if (vendorid == prod->amdsmu_vendorid && deviceid == prod->amdsmu_deviceid) { + + /* + * Some Krackan Point devices have different ip blocks + * based on CPU model. + */ + if (prod->model != 0x00 && model != prod->model) + continue; + if (product_out != NULL) *product_out = prod; return (true); @@ -105,7 +115,7 @@ amdsmu_cmd(device_t dev, enum amdsmu_msg msg, uint32_t arg, uint32_t *ret) amdsmu_write4(sc, SMU_REG_RESPONSE, SMU_RES_WAIT); /* Write out command to registers. */ - amdsmu_write4(sc, SMU_REG_MESSAGE, msg); + amdsmu_write4(sc, sc->product->amdsmu_msg, msg); amdsmu_write4(sc, SMU_REG_ARGUMENT, arg); /* Wait for SMU response and handle it. */ @@ -175,7 +185,7 @@ amdsmu_get_ip_blocks(device_t dev) sc->ip_blocks_active[i] = active; if (!active) continue; - printf("%s%s", amdsmu_ip_blocks_names[i], + printf("%s%s", sc->product->ip_blocks_names[i], i + 1 < sc->product->ip_block_count ? " " : "\n"); } @@ -193,10 +203,10 @@ amdsmu_get_ip_blocks(device_t dev) /* Create the sysctl node itself for the IP block. */ snprintf(sysctl_descr, sizeof sysctl_descr, "Metrics about the %s AMD IP block", - amdsmu_ip_blocks_names[i]); + sc->product->ip_blocks_names[i]); sc->ip_block_sysctlnodes[i] = SYSCTL_ADD_NODE(sc->sysctlctx, SYSCTL_CHILDREN(sc->ip_blocks_sysctlnode), OID_AUTO, - amdsmu_ip_blocks_names[i], CTLFLAG_RD, NULL, sysctl_descr); + sc->product->ip_blocks_names[i], CTLFLAG_RD, NULL, sysctl_descr); if (sc->ip_block_sysctlnodes[i] == NULL) { device_printf(dev, "could not add sysctl node for \"%s\"\n", sysctl_descr); diff --git a/sys/dev/amdsmu/amdsmu.h b/sys/dev/amdsmu/amdsmu.h index 4286d515ae77..0e7c4df37a43 100644 --- a/sys/dev/amdsmu/amdsmu.h +++ b/sys/dev/amdsmu/amdsmu.h @@ -14,7 +14,11 @@ #include <sys/bus.h> #include <sys/eventhandler.h> #include <sys/kernel.h> -#include <machine/bus.h> + +#include <machine/cpu.h> +#include <machine/md_var.h> +#include <machine/cputypes.h> +#include <machine/specialreg.h> #include <x86/cputypes.h> #include <dev/amdsmu/amdsmu_reg.h> @@ -22,26 +26,7 @@ #define SMU_RES_READ_PERIOD_US 50 #define SMU_RES_READ_MAX 20000 -static const struct amdsmu_product { - uint16_t amdsmu_vendorid; - uint16_t amdsmu_deviceid; - int16_t idlemask_reg; - size_t ip_block_count; -} amdsmu_products[] = { - { CPU_VENDOR_AMD, PCI_DEVICEID_AMD_CEZANNE_ROOT, - SMU_REG_IDLEMASK_CEZANNE, 12 }, - { CPU_VENDOR_AMD, PCI_DEVICEID_AMD_REMBRANDT_ROOT, - SMU_REG_IDLEMASK_PHOENIX, 12 }, - { CPU_VENDOR_AMD, PCI_DEVICEID_AMD_PHOENIX_ROOT, - SMU_REG_IDLEMASK_PHOENIX, 21 }, - /* - * XXX Strix Point (PCI_DEVICEID_AMD_STRIX_POINT_ROOT) doesn't support - * S0i3 and thus doesn't have an idlemask. Since our driver doesn't - * yet understand this, don't attach to Strix Point for the time being. - */ -}; - -static const char *const amdsmu_ip_blocks_names[] = { +static const char *amdsmu_ip_blocks_names[] = { "DISPLAY", "CPU", "GFX", @@ -66,7 +51,69 @@ static const char *const amdsmu_ip_blocks_names[] = { "VPE", }; -CTASSERT(nitems(amdsmu_ip_blocks_names) <= 32); +static const char *amdsmu_ip_blocks_names_v2[] = { + "DISPLAY", + "CPU", + "GFX", + "VDD", + "VDD_CCX", + "ACP", + "VCN_0", + "VCN_1", + "ISP", + "NBIO", + "DF", + "USB3_0", + "USB3_1", + "LAPIC", + "USB3_2", + "USB4_RT0", + "USB4_RT1", + "USB4_0", + "USB4_1", + "MPM", + "JPEG_0", + "JPEG_1", + "IPU", + "UMSCH", + "VPE", +}; + +#define IP_MAX_BLOCK_NAMES 32 + +CTASSERT(nitems(amdsmu_ip_blocks_names) <= IP_MAX_BLOCK_NAMES); +CTASSERT(nitems(amdsmu_ip_blocks_names_v2) <= IP_MAX_BLOCK_NAMES); + +static const struct amdsmu_product { + uint16_t amdsmu_vendorid; + uint16_t amdsmu_deviceid; + uint32_t model; + int16_t idlemask_reg; + size_t ip_block_count; + const char **ip_blocks_names; + uint32_t amdsmu_msg; +} amdsmu_products[] = { + { CPU_VENDOR_AMD, PCI_DEVICEID_AMD_CEZANNE_ROOT, 0x00, + SMU_REG_IDLEMASK_CEZANNE, 12 , amdsmu_ip_blocks_names, + SMU_REG_MSG_CEZANNE}, + { CPU_VENDOR_AMD, PCI_DEVICEID_AMD_REMBRANDT_ROOT, 0x00, + SMU_REG_IDLEMASK_PHOENIX, 12 , amdsmu_ip_blocks_names, + SMU_REG_MSG_CEZANNE}, + { CPU_VENDOR_AMD, PCI_DEVICEID_AMD_PHOENIX_ROOT, 0x00, + SMU_REG_IDLEMASK_PHOENIX, 21 , amdsmu_ip_blocks_names, + SMU_REG_MSG_CEZANNE}, + { CPU_VENDOR_AMD, PCI_DEVICEID_AMD_KRACKAN_POINT_ROOT, 0x00, + SMU_REG_IDLEMASK_KRACKAN, 22, amdsmu_ip_blocks_names, + SMU_REG_MSG_KRACKAN }, + { CPU_VENDOR_AMD, PCI_DEVICEID_AMD_KRACKAN_POINT_ROOT, 0x70, + SMU_REG_IDLEMASK_KRACKAN, 25, amdsmu_ip_blocks_names_v2, + SMU_REG_MSG_KRACKAN }, + /* + * XXX Strix Point (PCI_DEVICEID_AMD_STRIX_POINT_ROOT) doesn't support + * S0i3 and thus doesn't have an idlemask. Since our driver doesn't + * yet understand this, don't attach to Strix Point for the time being. + */ +}; struct amdsmu_softc { const struct amdsmu_product *product; @@ -88,14 +135,13 @@ struct amdsmu_softc { uint32_t active_ip_blocks; struct sysctl_oid *ip_blocks_sysctlnode; - struct sysctl_oid *ip_block_sysctlnodes[ - nitems(amdsmu_ip_blocks_names)]; - bool ip_blocks_active[ - nitems(amdsmu_ip_blocks_names)]; + struct sysctl_oid *ip_block_sysctlnodes[IP_MAX_BLOCK_NAMES]; + bool ip_blocks_active[IP_MAX_BLOCK_NAMES]; bus_space_handle_t metrics_space; struct amdsmu_metrics metrics; uint32_t idlemask; + uint32_t smu_msg; }; static inline uint32_t diff --git a/sys/dev/amdsmu/amdsmu_reg.h b/sys/dev/amdsmu/amdsmu_reg.h index 6afbcf006535..c71082072b60 100644 --- a/sys/dev/amdsmu/amdsmu_reg.h +++ b/sys/dev/amdsmu/amdsmu_reg.h @@ -16,6 +16,7 @@ * out? Also, there are way more of these. I couldn't find a centralized place * which lists them though. */ +#define PCI_DEVICEID_AMD_KRACKAN_POINT_ROOT 0x1122 #define PCI_DEVICEID_AMD_CEZANNE_ROOT 0x1630 #define PCI_DEVICEID_AMD_REMBRANDT_ROOT 0x14B5 #define PCI_DEVICEID_AMD_PHOENIX_ROOT 0x14E8 @@ -28,14 +29,18 @@ #define SMU_PHYSBASE_ADDR_HI 0x13B102EC #define SMU_MEM_SIZE 0x1000 + #define SMU_REG_SPACE_OFF 0x10000 -#define SMU_REG_MESSAGE 0x538 #define SMU_REG_RESPONSE 0x980 #define SMU_REG_ARGUMENT 0x9BC #define SMU_REG_IDLEMASK_CEZANNE 0x94 #define SMU_REG_IDLEMASK_PHOENIX 0xD14 +#define SMU_REG_IDLEMASK_KRACKAN 0xF14 + +#define SMU_REG_MSG_CEZANNE 0x538 +#define SMU_REG_MSG_KRACKAN 0x938 enum amdsmu_res { SMU_RES_WAIT = 0x00, diff --git a/sys/dev/asmc/asmc.c b/sys/dev/asmc/asmc.c index 0a701e6fd663..8cd7842d03fd 100644 --- a/sys/dev/asmc/asmc.c +++ b/sys/dev/asmc/asmc.c @@ -98,13 +98,15 @@ static void asmc_sms_calibrate(device_t dev); static int asmc_sms_intrfast(void *arg); static void asmc_sms_printintr(device_t dev, uint8_t); static void asmc_sms_task(void *arg, int pending); +static void asmc_sms_init(device_t dev); +static void asmc_detect_capabilities(device_t dev); #ifdef ASMC_DEBUG void asmc_dumpall(device_t); static int asmc_key_dump(device_t, int); #endif /* - * Model functions. + * Sysctl handlers. */ static int asmc_mb_sysctl_fanid(SYSCTL_HANDLER_ARGS); static int asmc_mb_sysctl_fanspeed(SYSCTL_HANDLER_ARGS); @@ -121,7 +123,7 @@ static int asmc_mbp_sysctl_light_left(SYSCTL_HANDLER_ARGS); static int asmc_mbp_sysctl_light_right(SYSCTL_HANDLER_ARGS); static int asmc_mbp_sysctl_light_control(SYSCTL_HANDLER_ARGS); static int asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS); -static int asmc_wol_sysctl(SYSCTL_HANDLER_ARGS); +static int asmc_aupo_sysctl(SYSCTL_HANDLER_ARGS); static int asmc_key_getinfo(device_t, const char *, uint8_t *, char *); @@ -138,474 +140,220 @@ static int asmc_sensor_read(device_t, const char *, int *); static int asmc_sensor_sysctl(SYSCTL_HANDLER_ARGS); static int asmc_detect_sensors(device_t); static int asmc_key_dump_by_index(device_t, int, char *, char *, uint8_t *); +static int asmc_key_search(device_t, const char *, unsigned int *); +static const char *asmc_temp_desc(const char *key); -struct asmc_model { - const char *smc_model; /* smbios.system.product env var. */ - const char *smc_desc; /* driver description */ - - /* Helper functions */ - int (*smc_sms_x)(SYSCTL_HANDLER_ARGS); - int (*smc_sms_y)(SYSCTL_HANDLER_ARGS); - int (*smc_sms_z)(SYSCTL_HANDLER_ARGS); - int (*smc_fan_id)(SYSCTL_HANDLER_ARGS); - int (*smc_fan_speed)(SYSCTL_HANDLER_ARGS); - int (*smc_fan_safespeed)(SYSCTL_HANDLER_ARGS); - int (*smc_fan_minspeed)(SYSCTL_HANDLER_ARGS); - int (*smc_fan_maxspeed)(SYSCTL_HANDLER_ARGS); - int (*smc_fan_targetspeed)(SYSCTL_HANDLER_ARGS); - int (*smc_light_left)(SYSCTL_HANDLER_ARGS); - int (*smc_light_right)(SYSCTL_HANDLER_ARGS); - int (*smc_light_control)(SYSCTL_HANDLER_ARGS); - - const char *smc_temps[ASMC_TEMP_MAX]; - const char *smc_tempnames[ASMC_TEMP_MAX]; - const char *smc_tempdescs[ASMC_TEMP_MAX]; +/* + * SMC temperature key descriptions. + * These are universal across all Intel Apple hardware. + */ +static const struct { + const char *key; + const char *desc; +} asmc_temp_descs[] = { + /* Ambient / airflow */ + { "TA0P", "Ambient" }, + { "TA0S", "PCIe Slot 1 Ambient" }, + { "TA0p", "Ambient Air" }, + { "TA1P", "Ambient 2" }, + { "TA1S", "PCIe Slot 1 PCB" }, + { "TA1p", "Ambient Air 2" }, + { "TA2P", "Ambient 3" }, + { "TA2S", "PCIe Slot 2 Ambient" }, + { "TA3S", "PCIe Slot 2 PCB" }, + { "TA0V", "Ambient" }, + { "TALP", "Ambient Light Proximity" }, + { "TaLC", "Airflow Left" }, + { "TaRC", "Airflow Right" }, + { "Ta0P", "Airflow Proximity" }, + /* Battery / enclosure */ + { "TB0T", "Enclosure Bottom" }, + { "TB1T", "Battery 1" }, + { "TB2T", "Battery 2" }, + { "TB3T", "Battery 3" }, + { "TBXT", "Battery" }, + { "Tb0P", "BLC Proximity" }, + /* CPU */ + { "TC0C", "CPU Core 1" }, + { "TC0D", "CPU Die" }, + { "TC0E", "CPU 1" }, + { "TC0F", "CPU 2" }, + { "TC0G", "CPU Package GPU" }, + { "TC0H", "CPU Heatsink" }, + { "TC0h", "CPU Heatsink" }, + { "TC0J", "CPU" }, + { "TC0P", "CPU Proximity" }, + { "TC0c", "CPU Core 1 PECI" }, + { "TC0d", "CPU Die PECI" }, + { "TC0p", "CPU Proximity" }, + { "TC1C", "CPU Core 2" }, + { "TC1c", "CPU Core 2 PECI" }, + { "TC1P", "CPU Proximity 2" }, + { "TC2C", "CPU Core 3" }, + { "TC2P", "CPU Proximity 3" }, + { "TC2c", "CPU Core 3 PECI" }, + { "TC3C", "CPU Core 4" }, + { "TC3P", "CPU Proximity 4" }, + { "TC3c", "CPU Core 4 PECI" }, + { "TC4C", "CPU Core 5" }, + { "TC5C", "CPU Core 6" }, + { "TC6C", "CPU Core 7" }, + { "TC7C", "CPU Core 8" }, + { "TC8C", "CPU Core 9" }, + { "TCGC", "PECI GPU" }, + { "TCGc", "PECI GPU" }, + { "TCHP", "Charger Proximity" }, + { "TCSA", "PECI SA" }, + { "TCSC", "PECI SA" }, + { "TCSc", "PECI SA" }, + { "TCTD", "CPU DTS" }, + { "TCXC", "PECI CPU" }, + { "TCXc", "PECI CPU" }, + { "TCPG", "CPU Package GPU" }, + { "TCXR", "CPU PECI DTS" }, + /* CPU dual-socket (Mac Pro) */ + { "TCAG", "CPU A Package" }, + { "TCAH", "CPU A Heatsink" }, + { "TCBG", "CPU B Package" }, + { "TCBH", "CPU B Heatsink" }, + /* GPU */ + { "TG0C", "GPU Core" }, + { "TG0D", "GPU Diode" }, + { "TG0H", "GPU Heatsink" }, + { "TG0M", "GPU Memory" }, + { "TG0P", "GPU Proximity" }, + { "TG0T", "GPU Diode" }, + { "TG0V", "GPU" }, + { "TG0d", "GPU Die" }, + { "TG0h", "GPU Heatsink" }, + { "TG0p", "GPU Proximity" }, + { "TGTV", "GPU" }, + { "TG1D", "GPU 2 Diode" }, + { "TG1H", "GPU 2 Heatsink" }, + { "TG1P", "GPU 2 Proximity" }, + { "TG1d", "GPU 2 Die" }, + { "TGVP", "GPU Memory Proximity" }, + /* Storage */ + { "TH0A", "SSD A" }, + { "TH0B", "SSD B" }, + { "TH0C", "SSD C" }, + { "TH0F", "SSD" }, + { "TH0O", "HDD" }, + { "TH0P", "HDD Proximity" }, + { "TH0R", "SSD" }, + { "TH0V", "SSD" }, + { "TH0a", "SSD A" }, + { "TH0b", "SSD B" }, + { "TH0c", "SSD C" }, + { "TH1O", "HDD 2" }, + { "TH1P", "HDD Bay 2" }, + { "TH2P", "HDD Bay 3" }, + { "TH3P", "HDD Bay 4" }, + { "Th0H", "Heatpipe 1" }, + { "Th0N", "SSD" }, + { "Th1H", "Heatpipe 2" }, + { "Th2H", "Heatpipe 3" }, + /* Thunderbolt */ + { "THSP", "Thunderbolt Proximity" }, + { "TI0P", "Thunderbolt 1" }, + { "TI0p", "Thunderbolt 1" }, + { "TI1P", "Thunderbolt 2" }, + { "TI1p", "Thunderbolt 2" }, + { "TTLD", "Thunderbolt Left" }, + { "TTRD", "Thunderbolt Right" }, + { "Te0T", "Thunderbolt Diode" }, + { "Te0t", "Thunderbolt Diode" }, + /* LCD */ + { "TL0P", "LCD Proximity" }, + { "TL0V", "LCD" }, + { "TL0p", "LCD Proximity" }, + { "TL1P", "LCD Panel 1" }, + { "TL1V", "LCD 1" }, + { "TL1p", "LCD Panel 1" }, + { "TL1v", "LCD 1" }, + { "TL2V", "LCD 2" }, + { "TLAV", "LCD" }, + { "TLBV", "LCD" }, + { "TLCV", "LCD" }, + /* Memory */ + { "TM0P", "Memory Proximity" }, + { "TM0S", "Memory Slot 1" }, + { "TM0p", "Memory Proximity" }, + { "TM1P", "Memory Riser A 2" }, + { "TM1S", "Memory Slot 2" }, + { "Tm0P", "Memory Proximity" }, + { "Tm0p", "Memory Proximity" }, + { "Tm1P", "Memory Proximity 2" }, + { "TMBS", "Memory Bank" }, + { "TMCD", "Memory DIMM" }, + /* Northbridge / MCH */ + { "TN0C", "Northbridge Core" }, + { "TN0D", "Northbridge Diode" }, + { "TN0H", "MCH Heatsink" }, + { "TN0P", "Northbridge Proximity" }, + { "TN1D", "MCH Die 2" }, + { "TN1P", "Northbridge Proximity 2" }, + /* PCH */ + { "TP0P", "PCH Proximity" }, + { "TP0p", "PCH Proximity" }, + { "TPCD", "PCH Die" }, + { "TPCd", "PCH Die" }, + /* Optical drive */ + { "TO0P", "Optical Drive" }, + { "TO0p", "Optical Drive" }, + /* Power supply */ + { "Tp0C", "Power Supply" }, + { "Tp0P", "Power Supply Proximity" }, + { "Tp1C", "Power Supply 2" }, + { "Tp1P", "Power Supply Component" }, + { "Tp1p", "Power Supply Component" }, + { "Tp2P", "Power Supply 2" }, + { "Tp2h", "Power Supply 2" }, + { "Tp2H", "Power Supply 2" }, + { "Tp3P", "Power Supply 3 Inlet" }, + { "Tp3h", "Power Supply 3" }, + { "Tp3H", "Power Supply 3" }, + { "Tp4P", "Power Supply 4" }, + { "Tp5P", "Power Supply 5" }, + /* Palm rest / trackpad */ + { "Ts0P", "Palm Rest" }, + { "Ts0S", "Memory Proximity" }, + { "Ts1P", "Palm Rest 2" }, + { "Ts1S", "Palm Rest 2" }, + /* Wireless */ + { "TW0P", "Wireless Proximity" }, + { "TW0p", "Wireless Proximity" }, + { "TBLR", "Bluetooth" }, + /* Camera */ + { "TS2P", "Camera Proximity" }, + { "TS2V", "Camera" }, + { "TS2p", "Camera Proximity" }, + /* Expansion */ + { "TS0C", "Expansion Slots" }, + { "TS0P", "Expansion Proximity" }, + { "TS0V", "Expansion" }, + { "TS0p", "Expansion Proximity" }, + /* Air vent */ + { "TV0P", "Air Vent" }, + /* VRM */ + { "Tv0S", "VRM 1" }, + { "Tv1S", "VRM 2" }, + /* Misc */ + { "TTF0", "Fan" }, + { "TMLB", "Logic Board" }, }; -static const struct asmc_model *asmc_match(device_t dev); - -#define ASMC_SMS_FUNCS \ - .smc_sms_x = asmc_mb_sysctl_sms_x, \ - .smc_sms_y = asmc_mb_sysctl_sms_y, \ - .smc_sms_z = asmc_mb_sysctl_sms_z - -#define ASMC_SMS_FUNCS_DISABLED \ - .smc_sms_x = NULL, \ - .smc_sms_y = NULL, \ - .smc_sms_z = NULL - -#define ASMC_FAN_FUNCS \ - .smc_fan_id = asmc_mb_sysctl_fanid, \ - .smc_fan_speed = asmc_mb_sysctl_fanspeed, \ - .smc_fan_safespeed = asmc_mb_sysctl_fansafespeed, \ - .smc_fan_minspeed = asmc_mb_sysctl_fanminspeed, \ - .smc_fan_maxspeed = asmc_mb_sysctl_fanmaxspeed, \ - .smc_fan_targetspeed = asmc_mb_sysctl_fantargetspeed - -#define ASMC_FAN_FUNCS2 \ - .smc_fan_id = asmc_mb_sysctl_fanid, \ - .smc_fan_speed = asmc_mb_sysctl_fanspeed, \ - .smc_fan_safespeed = NULL, \ - .smc_fan_minspeed = asmc_mb_sysctl_fanminspeed, \ - .smc_fan_maxspeed = asmc_mb_sysctl_fanmaxspeed, \ - .smc_fan_targetspeed = asmc_mb_sysctl_fantargetspeed - -#define ASMC_LIGHT_FUNCS \ - .smc_light_left = asmc_mbp_sysctl_light_left, \ - .smc_light_right = asmc_mbp_sysctl_light_right, \ - .smc_light_control = asmc_mbp_sysctl_light_control - -#define ASMC_LIGHT_FUNCS_10BYTE \ - .smc_light_left = asmc_mbp_sysctl_light_left_10byte, \ - .smc_light_right = NULL, \ - .smc_light_control = asmc_mbp_sysctl_light_control - -#define ASMC_LIGHT_FUNCS_DISABLED \ - .smc_light_left = NULL, \ - .smc_light_right = NULL, \ - .smc_light_control = NULL - -#define ASMC_TEMPS_FUNCS_DISABLED \ - .smc_temps = {}, \ - .smc_tempnames = {}, \ - .smc_tempdescs = {} \ - -static const struct asmc_model asmc_models[] = { - { - "MacBook1,1", "Apple SMC MacBook Core Duo", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED, - ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS - }, - - { - "MacBook2,1", "Apple SMC MacBook Core 2 Duo", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED, - ASMC_MB_TEMPS, ASMC_MB_TEMPNAMES, ASMC_MB_TEMPDESCS - }, - - { - "MacBook3,1", "Apple SMC MacBook Core 2 Duo", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED, - ASMC_MB31_TEMPS, ASMC_MB31_TEMPNAMES, ASMC_MB31_TEMPDESCS - }, - - { - "MacBook7,1", "Apple SMC MacBook Core 2 Duo (mid 2010)", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS_DISABLED, - ASMC_MB71_TEMPS, ASMC_MB71_TEMPNAMES, ASMC_MB71_TEMPDESCS - }, - - { - "MacBookPro1,1", "Apple SMC MacBook Pro Core Duo (15-inch)", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, - ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS - }, - - { - "MacBookPro1,2", "Apple SMC MacBook Pro Core Duo (17-inch)", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, - ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS - }, - - { - "MacBookPro2,1", "Apple SMC MacBook Pro Core 2 Duo (17-inch)", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, - ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS - }, - - { - "MacBookPro2,2", "Apple SMC MacBook Pro Core 2 Duo (15-inch)", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, - ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS - }, - - { - "MacBookPro3,1", "Apple SMC MacBook Pro Core 2 Duo (15-inch LED)", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, - ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS - }, - - { - "MacBookPro3,2", "Apple SMC MacBook Pro Core 2 Duo (17-inch HD)", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, - ASMC_MBP_TEMPS, ASMC_MBP_TEMPNAMES, ASMC_MBP_TEMPDESCS - }, - - { - "MacBookPro4,1", "Apple SMC MacBook Pro Core 2 Duo (Penryn)", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, - ASMC_MBP4_TEMPS, ASMC_MBP4_TEMPNAMES, ASMC_MBP4_TEMPDESCS - }, - - { - "MacBookPro5,1", "Apple SMC MacBook Pro Core 2 Duo (2008/2009)", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, - ASMC_MBP51_TEMPS, ASMC_MBP51_TEMPNAMES, ASMC_MBP51_TEMPDESCS - }, - - { - "MacBookPro5,5", "Apple SMC MacBook Pro Core 2 Duo (Mid 2009)", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS, - ASMC_MBP55_TEMPS, ASMC_MBP55_TEMPNAMES, ASMC_MBP55_TEMPDESCS - }, - - { - "MacBookPro6,2", "Apple SMC MacBook Pro (Mid 2010, 15-inch)", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, - ASMC_MBP62_TEMPS, ASMC_MBP62_TEMPNAMES, ASMC_MBP62_TEMPDESCS - }, - - { - "MacBookPro8,1", "Apple SMC MacBook Pro (early 2011, 13-inch)", - ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS, - ASMC_MBP81_TEMPS, ASMC_MBP81_TEMPNAMES, ASMC_MBP81_TEMPDESCS - }, - - { - "MacBookPro8,2", "Apple SMC MacBook Pro (early 2011)", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, - ASMC_MBP82_TEMPS, ASMC_MBP82_TEMPNAMES, ASMC_MBP82_TEMPDESCS - }, - - { - "MacBookPro8,3", "Apple SMC MacBook Pro (early 2011, 17-inch)", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS, - ASMC_MBP83_TEMPS, ASMC_MBP83_TEMPNAMES, ASMC_MBP83_TEMPDESCS - }, - - { - "MacBookPro9,1", "Apple SMC MacBook Pro (mid 2012, 15-inch)", - ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, - ASMC_MBP91_TEMPS, ASMC_MBP91_TEMPNAMES, ASMC_MBP91_TEMPDESCS - }, - - { - "MacBookPro9,2", "Apple SMC MacBook Pro (mid 2012, 13-inch)", - ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, - ASMC_MBP92_TEMPS, ASMC_MBP92_TEMPNAMES, ASMC_MBP92_TEMPDESCS - }, - - { - "MacBookPro11,2", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)", - ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS, - ASMC_MBP112_TEMPS, ASMC_MBP112_TEMPNAMES, ASMC_MBP112_TEMPDESCS - }, - - { - "MacBookPro11,3", "Apple SMC MacBook Pro Retina Core i7 (2013/2014)", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS, - ASMC_MBP113_TEMPS, ASMC_MBP113_TEMPNAMES, ASMC_MBP113_TEMPDESCS - }, - - { - "MacBookPro11,4", "Apple SMC MacBook Pro Retina Core i7 (mid 2015, 15-inch)", - ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS, - ASMC_MBP114_TEMPS, ASMC_MBP114_TEMPNAMES, ASMC_MBP114_TEMPDESCS - }, - - { - "MacBookPro11,5", - "Apple SMC MacBook Pro Retina Core i7 (mid 2015, 15-inch, AMD GPU)", - ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS, - ASMC_MBP115_TEMPS, ASMC_MBP115_TEMPNAMES, ASMC_MBP115_TEMPDESCS - }, - - { - "MacBookPro13,1", "Apple SMC MacBook Pro Retina Core i5 (late 2016, 13-inch)", - ASMC_SMS_FUNCS_DISABLED, ASMC_FAN_FUNCS2, ASMC_LIGHT_FUNCS, - ASMC_MBP131_TEMPS, ASMC_MBP131_TEMPNAMES, ASMC_MBP131_TEMPDESCS - }, - - /* The Mac Mini has no SMS */ - { - "Macmini1,1", "Apple SMC Mac Mini", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS, - ASMC_LIGHT_FUNCS_DISABLED, - ASMC_MM_TEMPS, ASMC_MM_TEMPNAMES, ASMC_MM_TEMPDESCS - }, - - /* The Mac Mini 2,1 has no SMS */ - { - "Macmini2,1", "Apple SMC Mac Mini 2,1", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS, - ASMC_LIGHT_FUNCS_DISABLED, - ASMC_MM21_TEMPS, ASMC_MM21_TEMPNAMES, ASMC_MM21_TEMPDESCS - }, - - /* The Mac Mini 3,1 has no SMS */ - { - "Macmini3,1", "Apple SMC Mac Mini 3,1", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS, - ASMC_LIGHT_FUNCS_DISABLED, - ASMC_MM31_TEMPS, ASMC_MM31_TEMPNAMES, ASMC_MM31_TEMPDESCS - }, - - /* The Mac Mini 4,1 (Mid-2010) has no SMS */ - { - "Macmini4,1", "Apple SMC Mac mini 4,1 (Mid-2010)", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS2, - ASMC_LIGHT_FUNCS_DISABLED, - ASMC_MM41_TEMPS, ASMC_MM41_TEMPNAMES, ASMC_MM41_TEMPDESCS - }, - - /* The Mac Mini 5,1 has no SMS */ - /* - same sensors as Mac Mini 5,2 */ - { - "Macmini5,1", "Apple SMC Mac Mini 5,1", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS2, - ASMC_LIGHT_FUNCS_DISABLED, - ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS - }, - - /* The Mac Mini 5,2 has no SMS */ - { - "Macmini5,2", "Apple SMC Mac Mini 5,2", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS2, - ASMC_LIGHT_FUNCS_DISABLED, - ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS - }, - - /* The Mac Mini 5,3 has no SMS */ - /* - same sensors as Mac Mini 5,2 */ - { - "Macmini5,3", "Apple SMC Mac Mini 5,3", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS2, - ASMC_LIGHT_FUNCS_DISABLED, - ASMC_MM52_TEMPS, ASMC_MM52_TEMPNAMES, ASMC_MM52_TEMPDESCS - }, - - /* The Mac Mini 6,1 has no SMS */ - { - "Macmini6,1", "Apple SMC Mac Mini 6,1", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS2, - ASMC_LIGHT_FUNCS_DISABLED, - ASMC_MM61_TEMPS, ASMC_MM61_TEMPNAMES, ASMC_MM61_TEMPDESCS - }, - - /* The Mac Mini 6,2 has no SMS */ - { - "Macmini6,2", "Apple SMC Mac Mini 6,2", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS2, - ASMC_LIGHT_FUNCS_DISABLED, - ASMC_MM62_TEMPS, ASMC_MM62_TEMPNAMES, ASMC_MM62_TEMPDESCS - }, - - /* The Mac Mini 7,1 has no SMS */ - { - "Macmini7,1", "Apple SMC Mac Mini 7,1", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS2, - ASMC_LIGHT_FUNCS_DISABLED, - ASMC_MM71_TEMPS, ASMC_MM71_TEMPNAMES, ASMC_MM71_TEMPDESCS - }, - - /* Idem for the Mac Pro "Quad Core" (original) */ - { - "MacPro1,1", "Apple SMC Mac Pro (Quad Core)", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS, - ASMC_LIGHT_FUNCS_DISABLED, - ASMC_MP1_TEMPS, ASMC_MP1_TEMPNAMES, ASMC_MP1_TEMPDESCS - }, - - /* Idem for the Mac Pro (Early 2008) */ - { - "MacPro3,1", "Apple SMC Mac Pro (Early 2008)", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS, - ASMC_LIGHT_FUNCS_DISABLED, - ASMC_MP31_TEMPS, ASMC_MP31_TEMPNAMES, ASMC_MP31_TEMPDESCS - }, - - /* Idem for the Mac Pro (8-core) */ - { - "MacPro2", "Apple SMC Mac Pro (8-core)", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS, - ASMC_LIGHT_FUNCS_DISABLED, - ASMC_MP2_TEMPS, ASMC_MP2_TEMPNAMES, ASMC_MP2_TEMPDESCS - }, - - /* Idem for the MacPro 2010*/ - { - "MacPro5,1", "Apple SMC MacPro (2010)", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS, - ASMC_LIGHT_FUNCS_DISABLED, - ASMC_MP5_TEMPS, ASMC_MP5_TEMPNAMES, ASMC_MP5_TEMPDESCS - }, - - /* Idem for the Mac Pro 2013 (cylinder) */ - { - "MacPro6,1", "Apple SMC Mac Pro (2013)", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS2, - ASMC_LIGHT_FUNCS_DISABLED, - ASMC_MP6_TEMPS, ASMC_MP6_TEMPNAMES, ASMC_MP6_TEMPDESCS - }, - - { - "MacBookAir1,1", "Apple SMC MacBook Air", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED, - ASMC_MBA_TEMPS, ASMC_MBA_TEMPNAMES, ASMC_MBA_TEMPDESCS - }, - - { - "MacBookAir3,1", "Apple SMC MacBook Air Core 2 Duo (Late 2010)", - ASMC_SMS_FUNCS, ASMC_FAN_FUNCS, ASMC_LIGHT_FUNCS_DISABLED, - ASMC_MBA3_TEMPS, ASMC_MBA3_TEMPNAMES, ASMC_MBA3_TEMPDESCS - }, - - { - "MacBookAir4,1", "Apple SMC Macbook Air 11-inch (Mid 2011)", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS2, - ASMC_LIGHT_FUNCS, - ASMC_MBA4_TEMPS, ASMC_MBA4_TEMPNAMES, ASMC_MBA4_TEMPDESCS - }, - - { - "MacBookAir4,2", "Apple SMC Macbook Air 13-inch (Mid 2011)", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS2, - ASMC_LIGHT_FUNCS, - ASMC_MBA4_TEMPS, ASMC_MBA4_TEMPNAMES, ASMC_MBA4_TEMPDESCS - }, - - { - "MacBookAir5,1", "Apple SMC MacBook Air 11-inch (Mid 2012)", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS2, - ASMC_LIGHT_FUNCS, - ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS - }, - - { - "MacBookAir5,2", "Apple SMC MacBook Air 13-inch (Mid 2012)", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS2, - ASMC_LIGHT_FUNCS, - ASMC_MBA5_TEMPS, ASMC_MBA5_TEMPNAMES, ASMC_MBA5_TEMPDESCS - }, - { - "MacBookAir6,1", "Apple SMC MacBook Air 11-inch (Early 2013)", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS2, - ASMC_LIGHT_FUNCS_10BYTE, - ASMC_MBA6_TEMPS, ASMC_MBA6_TEMPNAMES, ASMC_MBA6_TEMPDESCS - }, - { - "MacBookAir6,2", "Apple SMC MacBook Air 13-inch (Early 2013)", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS2, - ASMC_LIGHT_FUNCS_10BYTE, - ASMC_MBA6_TEMPS, ASMC_MBA6_TEMPNAMES, ASMC_MBA6_TEMPDESCS - }, - { - "MacBookAir7,1", "Apple SMC MacBook Air 11-inch (Early 2015)", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS2, - ASMC_LIGHT_FUNCS, - ASMC_MBA7_TEMPS, ASMC_MBA7_TEMPNAMES, ASMC_MBA7_TEMPDESCS - }, - { - "MacBookAir7,2", "Apple SMC MacBook Air 13-inch (Early 2015)", - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS2, - ASMC_LIGHT_FUNCS, - ASMC_MBA7_TEMPS, ASMC_MBA7_TEMPNAMES, ASMC_MBA7_TEMPDESCS - } -}; +static const char * +asmc_temp_desc(const char *key) +{ + unsigned int i; -static const struct asmc_model asmc_generic_models[] = { - { - .smc_model = "MacBookAir", - .smc_desc = NULL, - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS2, - ASMC_LIGHT_FUNCS, - ASMC_TEMPS_FUNCS_DISABLED - }, - { - .smc_model = "MacBookPro", - .smc_desc = NULL, - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS2, - ASMC_LIGHT_FUNCS, - ASMC_TEMPS_FUNCS_DISABLED - }, - { - .smc_model = "MacPro", - .smc_desc = NULL, - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS2, - ASMC_LIGHT_FUNCS_DISABLED, - ASMC_TEMPS_FUNCS_DISABLED - }, - { - .smc_model = "Macmini", - .smc_desc = NULL, - ASMC_SMS_FUNCS_DISABLED, - ASMC_FAN_FUNCS2, - ASMC_LIGHT_FUNCS_DISABLED, - ASMC_TEMPS_FUNCS_DISABLED + for (i = 0; i < nitems(asmc_temp_descs); i++) { + if (strcmp(asmc_temp_descs[i].key, key) == 0) + return (asmc_temp_descs[i].desc); } -}; - -#undef ASMC_SMS_FUNCS -#undef ASMC_SMS_FUNCS_DISABLED -#undef ASMC_FAN_FUNCS -#undef ASMC_FAN_FUNCS2 -#undef ASMC_LIGHT_FUNCS + return ("Temperature"); +} /* * Driver methods. @@ -651,44 +399,10 @@ DRIVER_MODULE(asmc, acpi, asmc_driver, NULL, NULL); MODULE_DEPEND(asmc, acpi, 1, 1, 1); MODULE_DEPEND(asmc, backlight, 1, 1, 1); -static const struct asmc_model * -asmc_match(device_t dev) -{ - const struct asmc_model *model; - char *model_name; - int i; - - model = NULL; - - model_name = kern_getenv("smbios.system.product"); - if (model_name == NULL) - goto out; - - for (i = 0; i < nitems(asmc_models); i++) { - if (strncmp(model_name, asmc_models[i].smc_model, - strlen(model_name)) == 0) { - model = &asmc_models[i]; - goto out; - } - } - for (i = 0; i < nitems(asmc_generic_models); i++) { - if (strncmp(model_name, asmc_generic_models[i].smc_model, - strlen(asmc_generic_models[i].smc_model)) == 0) { - model = &asmc_generic_models[i]; - goto out; - } - } - -out: - freeenv(model_name); - return (model); -} - static int asmc_probe(device_t dev) { - const struct asmc_model *model; - const char *device_desc; + char *product; int rv; if (resource_disabled("asmc", 0)) @@ -696,16 +410,9 @@ asmc_probe(device_t dev) rv = ACPI_ID_PROBE(device_get_parent(dev), dev, asmc_ids, NULL); if (rv > 0) return (rv); - - model = asmc_match(dev); - if (model == NULL) { - device_printf(dev, "model not recognized\n"); - return (ENXIO); - } - device_desc = model->smc_desc == NULL ? - model->smc_model : model->smc_desc; - device_set_desc(dev, device_desc); - + product = kern_getenv("smbios.system.product"); + device_set_descf(dev, "Apple %s", product ? product : "SMC"); + freeenv(product); return (rv); } @@ -718,7 +425,6 @@ asmc_attach(device_t dev) struct asmc_softc *sc = device_get_softc(dev); struct sysctl_ctx_list *sysctlctx; struct sysctl_oid *sysctlnode; - const struct asmc_model *model; sc->sc_ioport = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &sc->sc_rid_port, RF_ACTIVE); @@ -730,12 +436,20 @@ asmc_attach(device_t dev) sysctlctx = device_get_sysctl_ctx(dev); sysctlnode = device_get_sysctl_tree(dev); - model = asmc_match(dev); - mtx_init(&sc->sc_mtx, "asmc", NULL, MTX_SPIN); - sc->sc_model = model; - asmc_init(dev); + /* Read SMC revision, key count, fan count */ + ret = asmc_init(dev); + if (ret != 0) { + device_printf(dev, "SMC not responding\n"); + goto err; + } + + /* Probe SMC keys to detect capabilities */ + asmc_detect_capabilities(dev); + + /* Auto-detect and register voltage/current/power/ambient/temp sensors */ + asmc_detect_sensors(dev); /* * dev.asmc.n.fan.* tree. @@ -756,37 +470,43 @@ asmc_attach(device_t dev) SYSCTL_CHILDREN(sc->sc_fan_tree[i]), OID_AUTO, "id", CTLTYPE_STRING | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, j, - model->smc_fan_id, "I", "Fan ID"); + asmc_mb_sysctl_fanid, "I", "Fan ID"); SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(sc->sc_fan_tree[i]), OID_AUTO, "speed", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, j, - model->smc_fan_speed, "I", "Fan speed in RPM"); + asmc_mb_sysctl_fanspeed, "I", "Fan speed in RPM"); - SYSCTL_ADD_PROC(sysctlctx, - SYSCTL_CHILDREN(sc->sc_fan_tree[i]), - OID_AUTO, "safespeed", - CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, j, - model->smc_fan_safespeed, "I", "Fan safe speed in RPM"); + if (sc->sc_has_safespeed) { + SYSCTL_ADD_PROC(sysctlctx, + SYSCTL_CHILDREN(sc->sc_fan_tree[i]), + OID_AUTO, "safespeed", + CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, j, + asmc_mb_sysctl_fansafespeed, "I", + "Fan safe speed in RPM"); + } SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(sc->sc_fan_tree[i]), OID_AUTO, "minspeed", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j, - model->smc_fan_minspeed, "I", "Fan minimum speed in RPM"); + asmc_mb_sysctl_fanminspeed, "I", + "Fan minimum speed in RPM"); SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(sc->sc_fan_tree[i]), OID_AUTO, "maxspeed", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j, - model->smc_fan_maxspeed, "I", "Fan maximum speed in RPM"); + asmc_mb_sysctl_fanmaxspeed, "I", + "Fan maximum speed in RPM"); SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(sc->sc_fan_tree[i]), OID_AUTO, "targetspeed", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, dev, j, - model->smc_fan_targetspeed, "I", "Fan target speed in RPM"); + asmc_mb_sysctl_fantargetspeed, "I", + "Fan target speed in RPM"); SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(sc->sc_fan_tree[i]), @@ -803,19 +523,19 @@ asmc_attach(device_t dev) SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "temp", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "Temperature sensors"); - for (i = 0; model->smc_temps[i]; i++) { + for (i = 0; i < sc->sc_temp_count; i++) { SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(sc->sc_temp_tree), - OID_AUTO, model->smc_tempnames[i], + OID_AUTO, sc->sc_temp_sensors[i], CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, i, asmc_temp_sysctl, "I", - model->smc_tempdescs[i]); + asmc_temp_desc(sc->sc_temp_sensors[i])); } /* * dev.asmc.n.light */ - if (model->smc_light_left) { + if (sc->sc_has_light) { sc->sc_light_tree = SYSCTL_ADD_NODE(sysctlctx, SYSCTL_CHILDREN(sysctlnode), OID_AUTO, "light", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, @@ -825,21 +545,29 @@ asmc_attach(device_t dev) SYSCTL_CHILDREN(sc->sc_light_tree), OID_AUTO, "left", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, - dev, 0, model->smc_light_left, "I", - "Keyboard backlight left sensor"); + dev, 0, + sc->sc_light_len == ASMC_LIGHT_LONGLEN ? + asmc_mbp_sysctl_light_left_10byte : + asmc_mbp_sysctl_light_left, + "I", "Keyboard backlight left sensor"); - SYSCTL_ADD_PROC(sysctlctx, - SYSCTL_CHILDREN(sc->sc_light_tree), - OID_AUTO, "right", - CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, dev, 0, - model->smc_light_right, "I", - "Keyboard backlight right sensor"); + if (sc->sc_light_len != ASMC_LIGHT_LONGLEN && + asmc_key_getinfo(dev, ASMC_KEY_LIGHTRIGHT, + NULL, NULL) == 0) { + SYSCTL_ADD_PROC(sysctlctx, + SYSCTL_CHILDREN(sc->sc_light_tree), + OID_AUTO, "right", + CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, + dev, 0, + asmc_mbp_sysctl_light_right, "I", + "Keyboard backlight right sensor"); + } SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(sc->sc_light_tree), OID_AUTO, "control", CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_ANYBODY | CTLFLAG_MPSAFE, - dev, 0, model->smc_light_control, "I", + dev, 0, asmc_mbp_sysctl_light_control, "I", "Keyboard backlight brightness control"); sc->sc_kbd_bkl = backlight_register("asmc", dev); @@ -887,10 +615,15 @@ asmc_attach(device_t dev) "SMC key type (4 chars)"); #endif - if (model->smc_sms_x == NULL) + if (!sc->sc_has_sms) goto nosms; /* + * Initialize SMS hardware. + */ + asmc_sms_init(dev); + + /* * dev.asmc.n.sms tree. */ sc->sc_sms_tree = SYSCTL_ADD_NODE(sysctlctx, @@ -901,21 +634,21 @@ asmc_attach(device_t dev) SYSCTL_CHILDREN(sc->sc_sms_tree), OID_AUTO, "x", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, - dev, 0, model->smc_sms_x, "I", + dev, 0, asmc_mb_sysctl_sms_x, "I", "Sudden Motion Sensor X value"); SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(sc->sc_sms_tree), OID_AUTO, "y", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, - dev, 0, model->smc_sms_y, "I", + dev, 0, asmc_mb_sysctl_sms_y, "I", "Sudden Motion Sensor Y value"); SYSCTL_ADD_PROC(sysctlctx, SYSCTL_CHILDREN(sc->sc_sms_tree), OID_AUTO, "z", CTLTYPE_INT | CTLFLAG_RD | CTLFLAG_MPSAFE, - dev, 0, model->smc_sms_z, "I", + dev, 0, asmc_mb_sysctl_sms_z, "I", "Sudden Motion Sensor Z value"); /* @@ -970,6 +703,10 @@ asmc_detach(device_t dev) if (sc->sc_kbd_bkl != NULL) backlight_destroy(sc->sc_kbd_bkl); + /* Free temperature sensor key arrays */ + for (int i = 0; i < sc->sc_temp_count; i++) + free(sc->sc_temp_sensors[i], M_DEVBUF); + /* Free sensor key arrays */ for (int i = 0; i < sc->sc_voltage_count; i++) free(sc->sc_voltage_sensors[i], M_DEVBUF); @@ -1036,24 +773,73 @@ asmc_dumpall(device_t dev) } #endif +/* + * Initialize SMC: read revision, key count, fan count. + * SMS initialization is handled separately in asmc_sms_init(). + */ static int asmc_init(device_t dev) { struct asmc_softc *sc = device_get_softc(dev); struct sysctl_ctx_list *sysctlctx; uint8_t buf[6]; - int i, error = 1; + int error; sysctlctx = device_get_sysctl_ctx(dev); error = asmc_key_read(dev, ASMC_KEY_REV, buf, 6); if (error != 0) - goto out_err; + goto out; device_printf(dev, "SMC revision: %x.%x%x%x\n", buf[0], buf[1], buf[2], ntohs(*(uint16_t *)buf + 4)); - if (sc->sc_model->smc_sms_x == NULL) - goto nosms; + /* Auto power-on after AC power loss (AUPO). */ + if (asmc_key_read(dev, ASMC_KEY_AUPO, buf, 1) == 0) { + SYSCTL_ADD_PROC(sysctlctx, + SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), + OID_AUTO, "auto_poweron", + CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, + dev, 0, asmc_aupo_sysctl, "I", + "Auto power-on after AC power loss (0=off, 1=on)"); + } + + sc->sc_nfan = asmc_fan_count(dev); + if (sc->sc_nfan > ASMC_MAXFANS) { + device_printf(dev, + "more than %d fans were detected. Please report this.\n", + ASMC_MAXFANS); + sc->sc_nfan = ASMC_MAXFANS; + } + + /* + * Read and cache the number of SMC keys (32 bit buffer) + */ + if (asmc_key_read(dev, ASMC_NKEYS, buf, 4) == 0) { + sc->sc_nkeys = be32dec(buf); + if (bootverbose) + device_printf(dev, "number of keys: %d\n", + sc->sc_nkeys); + } else { + sc->sc_nkeys = 0; + } + +out: +#ifdef ASMC_DEBUG + asmc_dumpall(dev); +#endif + return (error); +} + +/* + * Initialize the Sudden Motion Sensor hardware. + * Called from asmc_attach() after capabilities are detected. + */ +static void +asmc_sms_init(device_t dev) +{ + struct asmc_softc *sc = device_get_softc(dev); + uint8_t buf[2]; + int i; /* * We are ready to receive interrupts from the SMS. @@ -1106,9 +892,8 @@ asmc_init(device_t dev) for (i = 0; i < 1000; i++) { if (asmc_key_read(dev, ASMC_KEY_SMS, buf, 2) == 0 && (buf[0] == ASMC_SMS_INIT1 && buf[1] == ASMC_SMS_INIT2)) { - error = 0; sc->sc_sms_intr_works = 1; - goto out; + goto done; } buf[0] = ASMC_SMS_INIT1; buf[1] = ASMC_SMS_INIT2; @@ -1118,50 +903,71 @@ asmc_init(device_t dev) } device_printf(dev, "WARNING: Sudden Motion Sensor not initialized!\n"); -out: +done: asmc_sms_calibrate(dev); -nosms: - /* Wake-on-LAN convenience sysctl */ - if (asmc_key_read(dev, ASMC_KEY_AUPO, buf, 1) == 0) { - SYSCTL_ADD_PROC(sysctlctx, - SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "wol", - CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE, - dev, 0, asmc_wol_sysctl, "I", - "Wake-on-LAN enable (0=off, 1=on)"); - } +} - sc->sc_nfan = asmc_fan_count(dev); - if (sc->sc_nfan > ASMC_MAXFANS) { - device_printf(dev, - "more than %d fans were detected. Please report this.\n", - ASMC_MAXFANS); - sc->sc_nfan = ASMC_MAXFANS; - } +/* + * Probe SMC keys to detect hardware capabilities. + */ +static void +asmc_detect_capabilities(device_t dev) +{ + struct asmc_softc *sc = device_get_softc(dev); + uint8_t len; + char type[ASMC_TYPELEN + 1]; - /* - * Read and cache the number of SMC keys (32 bit buffer) - */ - if (asmc_key_read(dev, ASMC_NKEYS, buf, 4) == 0) { - sc->sc_nkeys = be32dec(buf); - if (bootverbose) - device_printf(dev, "number of keys: %d\n", - sc->sc_nkeys); + /* SMS: require all keys used by asmc_sms_init() */ + sc->sc_has_sms = + (asmc_key_getinfo(dev, ASMC_KEY_SMS, + &len, type) == 0 && + asmc_key_getinfo(dev, ASMC_KEY_SMS_X, + &len, type) == 0 && + asmc_key_getinfo(dev, ASMC_KEY_SMS_Y, + &len, type) == 0 && + asmc_key_getinfo(dev, ASMC_KEY_SMS_Z, + &len, type) == 0 && + asmc_key_getinfo(dev, ASMC_KEY_SMS_LOW, + &len, type) == 0 && + asmc_key_getinfo(dev, ASMC_KEY_SMS_HIGH, + &len, type) == 0 && + asmc_key_getinfo(dev, ASMC_KEY_SMS_LOW_INT, + &len, type) == 0 && + asmc_key_getinfo(dev, ASMC_KEY_SMS_HIGH_INT, + &len, type) == 0 && + asmc_key_getinfo(dev, ASMC_KEY_SMS_FLAG, + &len, type) == 0 && + asmc_key_getinfo(dev, ASMC_KEY_INTOK, + &len, type) == 0); + + /* Light sensor: require ALV0 (len 6 or 10) and LKSB */ + if (asmc_key_getinfo(dev, ASMC_KEY_LIGHTLEFT, + &len, type) == 0 && + (len == ASMC_LIGHT_SHORTLEN || len == ASMC_LIGHT_LONGLEN) && + asmc_key_getinfo(dev, ASMC_KEY_LIGHTVALUE, + NULL, NULL) == 0) { + sc->sc_has_light = 1; + sc->sc_light_len = len; } else { - sc->sc_nkeys = 0; + sc->sc_has_light = 0; + sc->sc_light_len = 0; } - /* - * Auto-detect and register voltage/current/power/ambient sensors. - * Scans SMC keys and creates sysctls for detected sensors. - */ - asmc_detect_sensors(dev); + /* Fan safe speed */ + sc->sc_has_safespeed = + (asmc_key_getinfo(dev, ASMC_KEY_FANSAFESPEED0, + &len, type) == 0); -out_err: -#ifdef ASMC_DEBUG - asmc_dumpall(dev); -#endif - return (error); + /* Ambient light interrupt source */ + sc->sc_has_alsl = + (asmc_key_getinfo(dev, ASMC_KEY_LIGHTSRC, + &len, type) == 0); + + if (bootverbose) + device_printf(dev, + "capabilities: sms=%d light=%d (len=%d) safespeed=%d alsl=%d\n", + sc->sc_has_sms, sc->sc_has_light, sc->sc_light_len, + sc->sc_has_safespeed, sc->sc_has_alsl); } /* @@ -1416,7 +1222,7 @@ out: /* * Raw SMC key access sysctls - enables reading/writing any SMC key by name * Usage: - * sysctl dev.asmc.0.raw.key=AUPO # Set key, auto-detects length + * sysctl dev.asmc.0.raw.key=TC0P # Set key, auto-detects length * sysctl dev.asmc.0.raw.value # Read current value (hex bytes) * sysctl dev.asmc.0.raw.value=01 # Write new value */ @@ -1692,10 +1498,36 @@ asmc_sensor_sysctl(SYSCTL_HANDLER_ARGS) } /* - * Detect and register voltage/current/power/ambient sensors. - * Scans all SMC keys and identifies sensor keys by prefix. - * Returns 0 on success, -1 on error. + * Scan a range of SMC key indices, adding matching sensors. + * Only considers 2-byte keys with a supported type. */ +static void +asmc_scan_sensor_range(device_t dev, unsigned int start, + unsigned int end, char prefix, int *countp, char **sensors, + int maxcount) +{ + char key[ASMC_KEYLEN + 1]; + char type[ASMC_TYPELEN + 1]; + uint8_t len; + unsigned int i; + char *sensor_key; + + for (i = start; i < end; i++) { + if (asmc_key_dump_by_index(dev, i, key, type, &len)) + continue; + if (key[0] != prefix || len != 2) + continue; + if (!asmc_sensor_type_supported(type)) + continue; + if (*countp >= maxcount) + break; + sensor_key = malloc(ASMC_KEYLEN + 1, + M_DEVBUF, M_WAITOK); + memcpy(sensor_key, key, ASMC_KEYLEN + 1); + sensors[(*countp)++] = sensor_key; + } +} + static int asmc_detect_sensors(device_t dev) { @@ -1705,71 +1537,88 @@ asmc_detect_sensors(device_t dev) char key[ASMC_KEYLEN + 1]; char type[ASMC_TYPELEN + 1]; uint8_t len; - unsigned int nkeys; - unsigned int i; + unsigned int start, end, i; int error; char *sensor_key; - /* Initialize counts */ sc->sc_voltage_count = 0; sc->sc_current_count = 0; sc->sc_power_count = 0; sc->sc_light_count = 0; + sc->sc_temp_count = 0; if (sc->sc_nkeys == 0) return (0); - nkeys = sc->sc_nkeys; - - /* Scan all keys for voltage/current/power/ambient light sensors */ - for (i = 0; i < nkeys; i++) { - /* Get key name by index */ - error = asmc_key_dump_by_index(dev, i, key, type, &len); - if (error != 0) - continue; - if (!asmc_sensor_type_supported(type)) - continue; - /* Voltage sensors (VC*, VD*, VG*, VP*, VI*) */ - if (key[0] == 'V' && (key[1] == 'C' || key[1] == 'D' || - key[1] == 'G' || key[1] == 'P' || key[1] == 'I') && - len == 2) { - if (sc->sc_voltage_count >= ASMC_MAX_SENSORS) + /* + * Temperature sensors: binary search for T..U range, + * then filter by type sp78. + */ + error = asmc_key_search(dev, "T\0\0\0", &start); + if (error == 0) + error = asmc_key_search(dev, "U\0\0\0", &end); + if (error == 0) { + for (i = start; i < end; i++) { + if (asmc_key_dump_by_index(dev, i, + key, type, &len)) continue; - sensor_key = malloc(ASMC_KEYLEN + 1, - M_DEVBUF, M_WAITOK); - memcpy(sensor_key, key, ASMC_KEYLEN + 1); - sc->sc_voltage_sensors[sc->sc_voltage_count++] = - sensor_key; - } else if (key[0] == 'I' && (key[1] == 'C' || - key[1] == 'D' || key[1] == 'G' || key[1] == 'M' || - key[1] == 'N' || key[1] == 'O' || key[1] == 'H' || - key[1] == 'P' || key[1] == 'B' || key[1] == 'A' || - key[1] == 'L') && len == 2) { - /* Current sensors */ - if (sc->sc_current_count >= ASMC_MAX_SENSORS) + if (len != 2 || + strncmp(type, "sp78", 4) != 0) continue; + if (sc->sc_temp_count >= ASMC_TEMP_MAX) + break; sensor_key = malloc(ASMC_KEYLEN + 1, M_DEVBUF, M_WAITOK); memcpy(sensor_key, key, ASMC_KEYLEN + 1); - sc->sc_current_sensors[sc->sc_current_count++] = + sc->sc_temp_sensors[sc->sc_temp_count++] = sensor_key; - } else if (key[0] == 'P' && (key[1] == 'C' || - key[1] == 'D' || key[1] == 'N' || key[1] == 'S' || - key[1] == 'T' || key[1] == 'H' || key[1] == 'F' || - key[1] == 'Z' || key[1] == 'z') && len == 2) { - /* Power sensors */ - if (sc->sc_power_count >= ASMC_MAX_SENSORS) + } + } + + /* Voltage sensors: V..W range */ + error = asmc_key_search(dev, "V\0\0\0", &start); + if (error == 0) + error = asmc_key_search(dev, "W\0\0\0", &end); + if (error == 0) + asmc_scan_sensor_range(dev, start, end, 'V', + &sc->sc_voltage_count, sc->sc_voltage_sensors, + ASMC_MAX_SENSORS); + + /* Current sensors: I..J range */ + error = asmc_key_search(dev, "I\0\0\0", &start); + if (error == 0) + error = asmc_key_search(dev, "J\0\0\0", &end); + if (error == 0) + asmc_scan_sensor_range(dev, start, end, 'I', + &sc->sc_current_count, sc->sc_current_sensors, + ASMC_MAX_SENSORS); + + /* Power sensors: P..Q range */ + error = asmc_key_search(dev, "P\0\0\0", &start); + if (error == 0) + error = asmc_key_search(dev, "Q\0\0\0", &end); + if (error == 0) + asmc_scan_sensor_range(dev, start, end, 'P', + &sc->sc_power_count, sc->sc_power_sensors, + ASMC_MAX_SENSORS); + + /* Ambient light sensors: AL* in A..B range */ + error = asmc_key_search(dev, "A\0\0\0", &start); + if (error == 0) + error = asmc_key_search(dev, "B\0\0\0", &end); + if (error == 0) { + for (i = start; i < end; i++) { + if (asmc_key_dump_by_index(dev, i, + key, type, &len)) continue; - sensor_key = malloc(ASMC_KEYLEN + 1, - M_DEVBUF, M_WAITOK); - memcpy(sensor_key, key, ASMC_KEYLEN + 1); - sc->sc_power_sensors[sc->sc_power_count++] = - sensor_key; - } else if (key[0] == 'A' && key[1] == 'L' && - (key[2] == 'V' || key[2] == 'S') && len == 2) { - /* Ambient light sensors */ - if (sc->sc_light_count >= ASMC_MAX_SENSORS) + if (key[0] != 'A' || key[1] != 'L' || + (key[2] != 'V' && key[2] != 'S') || + len != 2) + continue; + if (!asmc_sensor_type_supported(type)) continue; + if (sc->sc_light_count >= ASMC_MAX_SENSORS) + break; sensor_key = malloc(ASMC_KEYLEN + 1, M_DEVBUF, M_WAITOK); memcpy(sensor_key, key, ASMC_KEYLEN + 1); @@ -1780,9 +1629,10 @@ asmc_detect_sensors(device_t dev) if (bootverbose) device_printf(dev, - "detected %d voltage, %d current, " + "detected %d temp, %d voltage, %d current, " "%d power, %d light sensors\n", - sc->sc_voltage_count, sc->sc_current_count, + sc->sc_temp_count, sc->sc_voltage_count, + sc->sc_current_count, sc->sc_power_count, sc->sc_light_count); /* Register sysctls for detected sensors */ @@ -1924,6 +1774,37 @@ out: return (error); } +/* + * Binary search for the first key index >= prefix. + * SMC keys are sorted, so this finds the lower bound efficiently. + */ +static int +asmc_key_search(device_t dev, const char *prefix, unsigned int *idx) +{ + struct asmc_softc *sc = device_get_softc(dev); + unsigned int lo, hi, mid; + char key[ASMC_KEYLEN + 1]; + char type[ASMC_TYPELEN + 1]; + uint8_t len; + int error; + + lo = 0; + hi = sc->sc_nkeys; + while (lo < hi) { + mid = lo + (hi - lo) / 2; + error = asmc_key_dump_by_index(dev, mid, + key, type, &len); + if (error != 0) + return (error); + if (strncmp(key, prefix, ASMC_KEYLEN) < 0) + lo = mid + 1; + else + hi = mid; + } + *idx = lo; + return (0); +} + static int asmc_key_write(device_t dev, const char *key, uint8_t *buf, uint8_t len) { @@ -2204,7 +2085,10 @@ asmc_temp_sysctl(SYSCTL_HANDLER_ARGS) struct asmc_softc *sc = device_get_softc(dev); int error, val; - val = asmc_temp_getvalue(dev, sc->sc_model->smc_temps[arg2]); + if (arg2 < 0 || arg2 >= sc->sc_temp_count) + return (EINVAL); + + val = asmc_temp_getvalue(dev, sc->sc_temp_sensors[arg2]); error = sysctl_handle_int(oidp, &val, 0, req); return (error); @@ -2263,6 +2147,10 @@ asmc_sms_intrfast(void *arg) sc->sc_sms_intrtype = type; asmc_sms_printintr(dev, type); + /* Don't queue SMS task for ambient light interrupts */ + if (type == ASMC_ALSL_INT2A && sc->sc_has_alsl) + return (FILTER_HANDLED); + taskqueue_enqueue(sc->sc_sms_tq, &sc->sc_sms_task); return (FILTER_HANDLED); } @@ -2285,10 +2173,9 @@ asmc_sms_printintr(device_t dev, uint8_t type) case ASMC_ALSL_INT2A: /* * This suppresses console and log messages for the ambient - * light sensor for models known to generate this interrupt. + * light sensor interrupt on models that have ALSL. */ - if (strcmp(sc->sc_model->smc_model, "MacBookPro5,5") == 0 || - strcmp(sc->sc_model->smc_model, "MacBookPro6,2") == 0) + if (sc->sc_has_alsl) break; /* FALLTHROUGH */ default: @@ -2451,18 +2338,17 @@ asmc_mbp_sysctl_light_left_10byte(SYSCTL_HANDLER_ARGS) } /* - * Wake-on-LAN convenience sysctl. - * Reading returns 1 if WoL is enabled, 0 if disabled. - * Writing 1 enables WoL, 0 disables it. + * Auto power-on after AC power loss (AUPO key). + * When non-zero the machine boots automatically when AC is restored + * after an unclean power loss. Useful for always-on servers / home labs. */ static int -asmc_wol_sysctl(SYSCTL_HANDLER_ARGS) +asmc_aupo_sysctl(SYSCTL_HANDLER_ARGS) { device_t dev = (device_t)arg1; uint8_t aupo; int val, error; - /* Read current AUPO value */ if (asmc_key_read(dev, ASMC_KEY_AUPO, &aupo, 1) != 0) return (EIO); @@ -2471,10 +2357,7 @@ asmc_wol_sysctl(SYSCTL_HANDLER_ARGS) if (error != 0 || req->newptr == NULL) return (error); - /* Clamp to 0 or 1 */ aupo = (val != 0) ? 1 : 0; - - /* Write AUPO */ if (asmc_key_write(dev, ASMC_KEY_AUPO, &aupo, 1) != 0) return (EIO); diff --git a/sys/dev/asmc/asmcvar.h b/sys/dev/asmc/asmcvar.h index 43f679f3fef0..6388fc78fb69 100644 --- a/sys/dev/asmc/asmcvar.h +++ b/sys/dev/asmc/asmcvar.h @@ -33,6 +33,9 @@ #define ASMC_TYPELEN 4 /* SMC type string length */ #define ASMC_MAX_SENSORS 64 /* Max sensors per type */ +/* Maximum number of auto-detected temperature sensors */ +#define ASMC_TEMP_MAX 80 + struct asmc_softc { device_t sc_dev; struct mtx sc_mtx; @@ -45,7 +48,6 @@ struct asmc_softc { struct sysctl_oid *sc_temp_tree; struct sysctl_oid *sc_sms_tree; struct sysctl_oid *sc_light_tree; - const struct asmc_model *sc_model; int sc_rid_port; int sc_rid_irq; struct resource *sc_ioport; @@ -74,6 +76,15 @@ struct asmc_softc { int sc_power_count; char *sc_light_sensors[ASMC_MAX_SENSORS]; int sc_light_count; + /* Auto-detected temperature sensors */ + char *sc_temp_sensors[ASMC_TEMP_MAX]; + int sc_temp_count; + /* Auto-detected capabilities */ + int sc_has_sms; + int sc_has_light; + int sc_light_len; /* ASMC_LIGHT_{SHORT,LONG}LEN */ + int sc_has_safespeed; + int sc_has_alsl; /* ALSL interrupt source */ }; /* @@ -150,9 +161,13 @@ struct asmc_softc { /* * Keyboard backlight. */ -#define ASMC_KEY_LIGHTLEFT "ALV0" /* RO; 6 bytes */ +#define ASMC_LIGHT_SHORTLEN 6 /* ALV0 short format */ +#define ASMC_LIGHT_LONGLEN 10 /* ALV0 long format (10-byte) */ +#define ASMC_KEY_LIGHTLEFT "ALV0" /* RO; 6 or 10 bytes */ #define ASMC_KEY_LIGHTRIGHT "ALV1" /* RO; 6 bytes */ #define ASMC_KEY_LIGHTVALUE "LKSB" /* WO; 2 bytes */ +#define ASMC_KEY_LIGHTSRC "ALSL" /* RO; ambient light source */ +#define ASMC_KEY_FANSAFESPEED0 "F0Sf" /* RO; 2 bytes */ /* * Clamshell. @@ -160,7 +175,9 @@ struct asmc_softc { #define ASMC_KEY_CLAMSHELL "MSLD" /* RO; 1 byte */ /* - * Auto power on / Wake-on-LAN. + * Auto power-on after AC power loss (AUPO). + * When set, the machine boots automatically when AC power is restored + * after an unclean power loss. This is NOT Wake-on-LAN. */ #define ASMC_KEY_AUPO "AUPO" /* RW; 1 byte */ @@ -168,945 +185,3 @@ struct asmc_softc { * Interrupt keys. */ #define ASMC_KEY_INTOK "NTOK" /* WO; 1 byte */ - -/* - * Temperatures. - * - * First for MacBook, second for MacBook Pro, third for Intel Mac Mini, - * fourth the Mac Pro 8-core and finally the MacBook Air. - * - */ -/* maximum array size for temperatures including the last NULL */ -#define ASMC_TEMP_MAX 80 -#define ASMC_MB_TEMPS { "TB0T", "TN0P", "TN1P", "Th0H", "Th1H", \ - "TM0P", NULL } -#define ASMC_MB_TEMPNAMES { "enclosure", "northbridge1", \ - "northbridge2", "heatsink1", \ - "heatsink2", "memory", } -#define ASMC_MB_TEMPDESCS { "Enclosure Bottomside", \ - "Northbridge Point 1", \ - "Northbridge Point 2", "Heatsink 1", \ - "Heatsink 2", "Memory Bank A", } - -#define ASMC_MB31_TEMPS { "TB0T", "TN0P", "Th0H", "Th1H", \ - "TM0P", NULL } - -#define ASMC_MB31_TEMPNAMES { "enclosure", "northbridge1", \ - "heatsink1", "heatsink2", \ - "memory", } - -#define ASMC_MB31_TEMPDESCS { "Enclosure Bottomside", \ - "Northbridge Point 1", \ - "Heatsink 1","Heatsink 2" \ - "Memory Bank A", } - -#define ASMC_MB71_TEMPS { "TB0T", "TB1T", "TB2T", "TC0D", "TC0P", \ - "TH0P", "TN0D", "TN0P", "TN0S", "TN1D", \ - "TN1E", "TN1F", "TN1G", "TN1S", "Th1H", \ - "Ts0P", "Ts0S", NULL } - -#define ASMC_MB71_TEMPNAMES { "enclosure_bottom0", "battery_1", "battery_2", "cpu_package", "cpu_proximity", \ - "hdd_bay", "northbridge0_diode", "northbridge0_proximity", "TN0S", "mpc_die2", \ - "TN1E", "TN1F", "TN1G", "TN1S", "heatsink1", \ - "palm_rest", "memory_proximity", } - -#define ASMC_MB71_TEMPDESCS { "Enclosure Bottom 0", "Battery 1", "Battery 2", "CPU Package", "CPU Proximity", \ - "HDD Bay", "Northbridge Diode", "Northbridge Proximity", "TN0S", "MPC Die 2", \ - "TN1E", "TN1F", "TN1G", "TN1S", "Heatsink 1", \ - "Palm Rest", "Memory Proximity", } - -#define ASMC_MBP_TEMPS { "TB0T", "Th0H", "Th1H", "Tm0P", \ - "TG0H", "TG0P", "TG0T", NULL } - -#define ASMC_MBP_TEMPNAMES { "enclosure", "heatsink1", \ - "heatsink2", "memory", "graphics", \ - "graphicssink", "unknown", } - -#define ASMC_MBP_TEMPDESCS { "Enclosure Bottomside", \ - "Heatsink 1", "Heatsink 2", \ - "Memory Controller", \ - "Graphics Chip", "Graphics Heatsink", \ - "Unknown", } - -#define ASMC_MBP4_TEMPS { "TB0T", "Th0H", "Th1H", "Th2H", "Tm0P", \ - "TG0H", "TG0D", "TC0D", "TC0P", "Ts0P", \ - "TTF0", "TW0P", NULL } - -#define ASMC_MBP4_TEMPNAMES { "enclosure", "heatsink1", "heatsink2", \ - "heatsink3", "memory", "graphicssink", \ - "graphics", "cpu", "cpu2", "unknown1", \ - "unknown2", "wireless", } - -#define ASMC_MBP4_TEMPDESCS { "Enclosure Bottomside", \ - "Main Heatsink 1", "Main Heatsink 2", \ - "Main Heatsink 3", \ - "Memory Controller", \ - "Graphics Chip Heatsink", \ - "Graphics Chip Diode", \ - "CPU Temperature Diode", "CPU Point 2", \ - "Unknown", "Unknown", \ - "Wireless Module", } - -#define ASMC_MBP51_TEMPS { "TB0T", "TB1T", "TB2T", "TB3T", "TC0D", \ - "TC0F", "TC0P", "TG0D", "TG0F", "TG0H", \ - "TG0P", "TG0T", "TG1H", "TN0D", "TN0P", \ - "TTF0", "Th2H", "Tm0P", "Ts0P", "Ts0S", \ - NULL } - -#define ASMC_MBP51_TEMPNAMES { "enclosure_bottom_0", "enclosure_bottom_1", \ - "enclosure_bottom_2", "enclosure_bottom_3", \ - "cpu_diode", "cpu", \ - "cpu_pin", "gpu_diode", \ - "gpu", "gpu_heatsink", \ - "gpu_pin", "gpu_transistor", \ - "gpu_2_heatsink", "northbridge_diode", \ - "northbridge_pin", "unknown", \ - "heatsink_2", "memory_controller", \ - "pci_express_slot_pin", "pci_express_slot_unk" } - -#define ASMC_MBP51_TEMPDESCS { "Enclosure Bottom 0", "Enclosure Bottom 1", \ - "Enclosure Bottom 2", "Enclosure Bottom 3", \ - "CPU Diode", "CPU ???", \ - "CPU Pin", "GPU Diode", \ - "GPU ???", "GPU Heatsink", \ - "GPU Pin", "GPU Transistor", \ - "GPU 2 Heatsink", "Northbridge Diode", \ - "Northbridge Pin", "Unknown", \ - "Heatsink 2", "Memory Controller", \ - "PCI Express Slot Pin", "PCI Express Slot (unk)" } - -#define ASMC_MBP62_TEMPS { "TB0T", "TB1T", "TB2T", \ - "TC0C", "TC0D", "TC0P", \ - "TC1C", "TG0D", "TG0P", \ - "TG0T", "TMCD", "TP0P", \ - "TPCD", "Th1H", "Th2H", \ - "Tm0P", "Ts0P", "Ts0S" } - -#define ASMC_MBP62_TEMPNAMES { "enclosure_bottom_0", "enclosure_bottom_1", \ - "enclosure_bottom_2", "cpu0", \ - "cpu_diode", "cpu_proximity", \ - "cpu1", "gpu_diode", \ - "gpu_pin", "gpu_transistor", \ - "TMCD", "pch_controller_proximity", \ - "pch_die", "heatsink1", \ - "heatsink2", "memory-controller", \ - "palmrest", "memoryproximity" } - -#define ASMC_MBP62_TEMPDESCS { "Enclosure Bottom 0", "Enclosure Bottom 1", \ - "Enclosure Bottom 2", "CPU 0", \ - "CPU Diode", "CPU Proximity", \ - "CPU 1", "GPU Diode", \ - "GPU Pin", "GPU Transistor", \ - "TMCD", "PCH Controller Proximity", \ - "PCH Die", "Heat Sink 1", \ - "Heat Sink 2", "Memory Controller", \ - "Palm Rest", "Memory Proximity" } - -#define ASMC_MBP55_TEMPS { "TB0T", "TB1T", \ - "TB2T", "TB3T", \ - "TC0D", "TC0P", \ - "TN0D", "TN0P", \ - "TTF0", \ - "Th0H", "Th1H", "ThFH", \ - "Ts0P", "Ts0S", \ - NULL } - -#define ASMC_MBP55_TEMPNAMES { "enclosure_bottom_0", "enclosure_bottom_1", \ - "enclosure_bottom_2", "enclosure_bottom_3", \ - "cpu_diode", "cpu_pin", \ - "northbridge_diode", "northbridge_pin", \ - "unknown", \ - "heatsink_0", "heatsink_1", "heatsink_2", \ - "pci_express_slot_pin", "pci_express_slot_unk" } - -#define ASMC_MBP55_TEMPDESCS { "Enclosure Bottom 0", "Enclosure Bottom 1", \ - "Enclosure Bottom 2", "Enclosure Bottom 3", \ - "CPU Diode", "CPU Pin", \ - "Northbridge Diode", "Northbridge Pin", \ - "Unknown", \ - "Heatsink 0", "Heatsink 1", "Heatsink 2", \ - "PCI Express Slot Pin", "PCI Express Slot (unk)" } - -#define ASMC_MBP81_TEMPS { "TB0T", "TB1T", "TB2T", "TC0C", "TC0D", \ - "TC0E", "TC0F", "TC0P", "TC1C", "TC2C", \ - "TCFC", "TCGC", "TCSA", "TM0S", "TMBS", \ - "TP0P", "TPCD", "TW0P", "Th1H", "Ts0P", \ - "Ts0S", NULL } - -#define ASMC_MBP81_TEMPNAMES { "enclosure", "TB1T", "TB2T", "TC0C", "TC0D", \ - "TC0E", "TC0F", "TC0P", "TC1C", "TC2C", \ - "TCFC", "TCGC", "TCSA", "TM0S", "TMBS", \ - "TP0P", "TPCD", "wireless", "Th1H", "Ts0P", \ - "Ts0S" } - -#define ASMC_MBP81_TEMPDESCS { "Enclosure Bottomside", "TB1T", "TB2T", "TC0C", "TC0D", \ - "TC0E", "TC0F", "TC0P", "TC1C", "TC2C", \ - "TCFC", "TCGC", "TCSA", "TM0S", "TMBS", \ - "TP0P", "TPCD", "TW0P", "Th1H", "Ts0P", \ - "Ts0S" } - -#define ASMC_MBP82_TEMPS { "TB0T", "TB1T", "TB2T", "TC0C", "TC0D", \ - "TC0E", "TC0F", "TC0P", "TC1C", "TC2C", \ - "TC3C", "TC4C", "TCFC", "TCGC", "TCSA", \ - "TCTD", "TG0D", "TG0P", "THSP", "TM0S", \ - "TMBS", "TP0P", "TPCD", "TW0P", "Th1H", \ - "Th2H", "Tm0P", "Ts0P", "Ts0S", NULL } - -#define ASMC_MBP82_TEMPNAMES { "enclosure", "TB1T", "TB2T", "TC0C", "TC0D", \ - "TC0E", "TC0F", "TC0P", "TC1C", "TC2C", \ - "TC3C", "TC4C", "TCFC", "TCGC", "TCSA", \ - "TCTD", "graphics", "TG0P", "THSP", "TM0S", \ - "TMBS", "TP0P", "TPCD", "wireless", "Th1H", \ - "Th2H", "memory", "Ts0P", "Ts0S" } - -#define ASMC_MBP82_TEMPDESCS { "Enclosure Bottomside", "TB1T", "TB2T", "TC0C", "TC0D", \ - "TC0E", "TC0F", "TC0P", "TC1C", "TC2C", \ - "TC3C", "TC4C", "TCFC", "TCGC", "TCSA", \ - "TCTD", "TG0D", "TG0P", "THSP", "TM0S", \ - "TMBS", "TP0P", "TPCD", "TW0P", "Th1H", \ - "Th2H", "Tm0P", "Ts0P", "Ts0S" } - -#define ASMC_MBP83_TEMPS { "ALSL", "F0Ac", "F1Ac", "IB0R", "IC0R", \ - "ID0R", "IG0R", "IO0R", "PCPC", "PCPG", \ - "PCPT", "PD0R", "TB1T", "TB2T", "TC0C", \ - "TC0D", "TC0P", "TC1C", "TC2C", "TC3C", \ - "TC4C", "TG0D", "TG0P", "THSP", "TP0P", \ - "TPCD", "Th1H", "Th2H", "Tm0P", "Ts0P", \ - "VC0C", "VD0R", "VG0C", "VN0C", "VP0R", NULL } - -#define ASMC_MBP83_TEMPNAMES { "ambient_light", "fan_leftside", "fan_rightside", \ - "battery_current", "cpu_vcorevtt", "dc_current", \ - "gpu_voltage", "other", "cpu_package_core", \ - "cpu_package_gpu", "cpu_package_total", "dc_in", \ - "battery_1", "battery_2", "cpu_die_digital", \ - "cpu_die_analog", "cpu_proximity", "cpu_core_1", \ - "cpu_core_2", "cpu_core_3", "cpu_core_4", "gpu_die_analog", \ - "gpu_proximity", "thunderbolt", "platform_controller", \ - "pch_die_digital", "right_fin_stack", "left_fin_stack", \ - "dc_in_air_flow", "palm_rest", "cpu_vcore", "dc_in_voltage", \ - "gpu_vcore", "intel_gpu_vcore", "pbus_voltage" } - -#define ASMC_MBP83_TEMPDESCS { "Ambient Light", "Fan Leftside", "Fan Rightside", \ - "Battery BMON Current", "CPU VcoreVTT", "DC In AMON Current", \ - "GPU Voltage", "Other 5V 3V", "CPU Package Core", \ - "CPU Package GPU", "CPU Package Total", "DC In", \ - "Battery Sensor 1", "Battery Sensor 2", "CPU Die Digital", \ - "CPU Die Analog", "CPU Proximity", "CPU Core 1 DTS", \ - "CPU Core 2 DTS", "CPU Core 3 DTS", "CPU Core 4 DTS", \ - "GPU Die Analog", "GPU Proximity", "Thunderbolt Proximity", \ - "Platform Controller Hub", "PCH Die Digital", \ - "Right Fin Stack Proximity", "Left Fin Stack Proximity", \ - "DC In Proximity Air Flow", "Palm Rest", "CPU VCore", \ - "DC In Voltage", "GPU VCore", "Intel GPU VCore", "PBus Voltage" } - -#define ASMC_MBP91_TEMPS { "TA0P", "TB0T", "TB1T", "TB2T", "TC0E", \ - "TC0F", "TC0P", "TC1C", "TC2C", "TC3C", \ - "TC4C", "TCGC", "TCSA", "TCXC", "TG0D", \ - "TG0P", "TG1D", "TG1F", "TG1d", "TGTC", \ - "TGTD", "TM0P", "TM0S", "TP0P", "TPCD", \ - "Th1H", "Th2H", "Ts0P", "Ts0S", "Tsqf", NULL } - -#define ASMC_MBP91_TEMPNAMES { "ambient", "enclosure_bottom_1", "enclosure_bottom_2", \ - "enclosure_bottom_3", "cpu_die_peci_0", "cpu_die_peci_1", \ - "cpu_proximity", "cpu_core_1", "cpu_core_2", "cpu_core_3", \ - "cpu_core_4", "intel_gpu", "cpu_sys_agent", \ - "cpu_core_peci", "gpu_analog", \ - "gpu_proximity", "geforce_gpu_digital", "tg1f", \ - "gpu_2_die", "tgtc", "tgtd", "memory_proximity", \ - "mem_bank_a1", "platform_ctrl_hub", "pch_digital", \ - "main_heatsink_r", "main_heatsink_l", "palm_rest", \ - "bottom_skin", "tsqf" } - -#define ASMC_MBP91_TEMPDESCS { "Ambient", "Enclosure Bottom 1", "Enclosure Bottom 2", \ - "Enclosure Bottom 3", "CPU Die PECI 0", "CPU Die PECI 1", \ - "CPU Proximity", "CPU Core 1", "CPU Core 2", \ - "CPU Core 3", "CPU Core 4", "Intel GPU", \ - "CPU System Agent Core", "CPU Core - PECI", \ - "GPU Die - Analog", "GPU Proximity", \ - "GeForce GPU Die - Digital", "TG1F", "GPU 2 Die" \ - "TGTC", "TGTD", "Memory Proximity", \ - "Memory Bank A1", "Platform Controller Hub", "PCH Die - Digital", \ - "Main Heatsink Right", "Main Heatsink Left", "Palm Rest", \ - "Bottom Skin", "Tsqf" } - -#define ASMC_MBP92_TEMPS { "Ts0P", "Ts0S", "TA0P", "TB1T", "TB2T", \ - "TB0T", "TC1C", "TC2C", "TC0E", "TC0F", \ - "TC0J", "TC0P", "TCFC", "TCGC", "TCSA", \ - "TCTD", "TCXC", "TG1D", "TM0P", "TM0S", \ - "TPCD", NULL } - -#define ASMC_MBP92_TEMPNAMES { "Ts0P", "Ts0S", "TA0P", "TB1T", "TB2T", \ - "TB0T", "TC1C", "TC2C", "TC0E", "TC0F", \ - "TC0J", "TC0P", "TCFC", "TCGC", "TCSA", \ - "TCTD", "TCXC", "TG1D", "TM0P", "TM0S", \ - "TPCD" } - -#define ASMC_MBP92_TEMPDESCS { "Palm Rest", "Memory Proximity", "Airflow 1", \ - "Battery 1", "Battery 2", "Battery TS_MAX", \ - "CPU Core 1", "CPU Core 2", "CPU1", "CPU1", \ - "TC0J", "CPU 1 Proximity", "TCFC", \ - "PECI GPU", "PECI SA", "TCTD", "PECI CPU", \ - "GPU Die", "Memory Bank A1", "Memory Module A1", \ - "PCH Die" } - -#define ASMC_MBP112_TEMPS { "TB0T", "TB1T", "TB2T", "TBXT", "TC0E", \ - "TC0F", "TC0P", "TC1C", "TC2C", "TC3C", \ - "TC4C", "TCFC", "TCGC", "TCSA", "TCTD", \ - "TCXC", "TH0A", "TH0B", "TH0F", "TH0R", \ - "TH0V", "TH0a", "TH0b", "TH0c", "TM0P", \ - "TM0S", "TP0P", "TPCD", "TW0P", "Ta0P", \ - "TaSP", "Th1H", "Th2H", "Ts0P", "Ts0S", \ - "Ts1S", NULL } - -#define ASMC_MBP112_TEMPNAMES { "TB0T", "TB1T", "TB2T", "TBXT", "TC0E", \ - "TC0F", "TC0P", "TC1C", "TC2C", "TC3C", \ - "TC4C", "TCFC", "TCGC", "TCSA", "TCTD", \ - "TCXC", "TH0A", "TH0B", "TH0F", "TH0R", \ - "TH0V", "TH0a", "TH0b", "TH0c", "TM0P", \ - "TM0S", "TP0P", "TPCD", "TW0P", "Ta0P", \ - "TaSP", "Th1H", "Th2H", "Ts0P", "Ts0S", \ - "Ts1S" } - -#define ASMC_MBP112_TEMPDESCS { "TB0T", "TB1T", "TB2T", "TBXT", "TC0E", \ - "TC0F", "TC0P", "TC1C", "TC2C", "TC3C", \ - "TC4C", "TCFC", "TCGC", "TCSA", "TCTD", \ - "TCXC", "TH0A", "TH0B", "TH0F", "TH0R", \ - "TH0V", "TH0a", "TH0b", "TH0c", "TM0P", \ - "TM0S", "TP0P", "TPCD", "TW0P", "Ta0P", \ - "TaSP", "Th1H", "Th2H", "Ts0P", "Ts0S", \ - "Ts1S" } - -#define ASMC_MBP113_TEMPS { "TB0T", "TB1T", "TB2T", "TBXT", "TC0E", \ - "TC0F", "TC0P", "TC1C", "TC2C", "TC3C", \ - "TC4C", "TCFC", "TCGC", "TCSA", "TCTD", \ - "TCXC", "TG0D", "TG0P", "TG1D", "TG1F", \ - "TG1d", "TH0A", "TH0B", "TH0F", "TH0R", \ - "TH0V", "TH0a", "TH0b", "TH0c", "TM0P", \ - "TM0S", "TP0P", "TPCD", "TW0P", "Ta0P", \ - "TaSP", "Th1H", "Th2H", "Ts0P", "Ts0S", \ - "Ts1S", NULL } - -#define ASMC_MBP113_TEMPNAMES { "TB0T", "TB1T", "TB2T", "TBXT", "TC0E", \ - "TC0F", "TC0P", "TC1C", "TC2C", "TC3C", \ - "TC4C", "TCFC", "TCGC", "TCSA", "TCTD", \ - "TCXC", "TG0D", "TG0P", "TG1D", "TG1F", \ - "TG1d", "TH0A", "TH0B", "TH0F", "TH0R", \ - "TH0V", "TH0a", "TH0b", "TH0c", "TM0P", \ - "TM0S", "TP0P", "TPCD", "TW0P", "Ta0P", \ - "TaSP", "Th1H", "Th2H", "Ts0P", "Ts0S", \ - "Ts1S" } - -#define ASMC_MBP113_TEMPDESCS { "TB0T", "TB1T", "TB2T", "TBXT", "TC0E", \ - "TC0F", "TC0P", "TC1C", "TC2C", "TC3C", \ - "TC4C", "TCFC", "TCGC", "TCSA", "TCTD", \ - "TCXC", "TG0D", "TG0P", "TG1D", "TG1F", \ - "TG1d", "TH0A", "TH0B", "TH0F", "TH0R", \ - "TH0V", "TH0a", "TH0b", "TH0c", "TM0P", \ - "TM0S", "TP0P", "TPCD", "TW0P", "Ta0P", \ - "TaSP", "Th1H", "Th2H", "Ts0P", "Ts0S", \ - "Ts1S" } - -#define ASMC_MBP114_TEMPS { "IC0C", "ID0R", "IHDC", "IPBR", "IC0R", \ - "IO3R", "IO5R", "IM0C", "IC1C", "IC2C", \ - "IC3C", "ILDC", "IBLC", "IAPC", "IHSC", \ - "ICMC", "TC0P", "TP0P", "TM0P", \ - "Ta0P", "Th2H", "Th1H", "TW0P", "Ts0P", \ - "Ts1P", "TB0T", "TB1T", "TB2T", "TH0A", "TH0B", \ - "TC1C", "TC2C", "TC3C", "TC4C", "TCXC", \ - "TCGC", "TPCD", "TCSA", "VC0C", "VD0R", \ - "VP0R", "ALSL", "F0Ac", "F1Ac", "PCPC", \ - "PCPG", "PCPT", "PSTR", "PDTR", NULL } - -#define ASMC_MBP114_TEMPNAMES { "IC0C", "ID0R", "IHDC", "IPBR", "IC0R", \ - "IO3R", "IO5R", "IM0C", "IC1C", "IC2C", \ - "IC3C", "ILDC", "IBLC", "IAPC", "IHSC", \ - "ICMC", "TC0P", "TP0P", "TM0P", \ - "Ta0P", "Th2H", "Th1H", "TW0P", "Ts0P", \ - "Ts1P", "TB0T", "TB1T", "TB2T", "TH0A", "TH0B", \ - "TC1C", "TC2C", "TC3C", "TC4C", "TCXC", \ - "TCGC", "TPCD", "TCSA", "VC0C", "VD0R", \ - "VP0R", "ALSL", "F0Ac", "F1Ac", "PCPC", \ - "PCPG", "PCPT", "PSTR", "PDTR" } - -#define ASMC_MBP114_TEMPDESCS { "CPU High (CPU, I/O)", "DC In", "SSD", "Charger (BMON)", "CPU", \ - "Other 3.3V", "Other 5V", "Memory", "Platform Controller Hub Core", "CPU Load Current Monitor", \ - "CPU DDR", "LCD Panel", "LCD Backlight", "Airport", "Thunderbolt", \ - "S2", "CPU Proximity", "Platform Controller Hub", "Memory Proximity", "Air Flow Proximity", \ - "Left Fin Stack", "Right Fin Stack", "Airport Proximity", "Palm Rest", "Palm Rest Actuator", \ - "Battery Max", "Battery Sensor 1", "Battery Sensor 2", "SSD A", "SSD B", \ - "CPU Core 1", "CPU Core 2", "CPU Core 3", "CPU Core 4", "CPU PECI Die", \ - "Intel GPU", "Platform Controller Hub PECI", "CPU System Agent Core", "CPU VCore", "DC In", \ - "Pbus", "Ambient Light", "Leftside", "Rightside", "CPU Package Core", \ - "CPU Package GPU", "CPU Package Total", "System Total", "DC In" } - -/* MacBookPro11,5 - same as 11,4 but without IBLC, ICMC, and IC2C keys */ -#define ASMC_MBP115_TEMPS { "IC0C", "ID0R", "IHDC", "IPBR", "IC0R", \ - "IO3R", "IO5R", "IM0C", "IC1C", \ - "IC3C", "ILDC", "IAPC", "IHSC", \ - "TC0P", "TP0P", "TM0P", \ - "Ta0P", "Th2H", "Th1H", "TW0P", "Ts0P", \ - "Ts1P", "TB0T", "TB1T", "TB2T", "TH0A", "TH0B", \ - "TC1C", "TC2C", "TC3C", "TC4C", "TCXC", \ - "TCGC", "TPCD", "TCSA", "VC0C", "VD0R", \ - "VP0R", "ALSL", "F0Ac", "F1Ac", "PCPC", \ - "PCPG", "PCPT", "PSTR", "PDTR", NULL } - - -#define ASMC_MBP115_TEMPNAMES { "IC0C", "ID0R", "IHDC", "IPBR", "IC0R", \ - "IO3R", "IO5R", "IM0C", "IC1C", \ - "IC3C", "ILDC", "IAPC", "IHSC", \ - "TC0P", "TP0P", "TM0P", \ - "Ta0P", "Th2H", "Th1H", "TW0P", "Ts0P", \ - "Ts1P", "TB0T", "TB1T", "TB2T", "TH0A", "TH0B", \ - "TC1C", "TC2C", "TC3C", "TC4C", "TCXC", \ - "TCGC", "TPCD", "TCSA", "VC0C", "VD0R", \ - "VP0R", "ALSL", "F0Ac", "F1Ac", "PCPC", \ - "PCPG", "PCPT", "PSTR", "PDTR" } - -#define ASMC_MBP115_TEMPDESCS { "CPU High (CPU, I/O)", "DC In", "SSD", "Charger (BMON)", "CPU", \ - "Other 3.3V", "Other 5V", "Memory", "Platform Controller Hub Core", \ - "CPU DDR", "LCD Panel", "Airport", "Thunderbolt", \ - "CPU Proximity", "Platform Controller Hub", "Memory Proximity", "Air Flow Proximity", \ - "Left Fin Stack", "Right Fin Stack", "Airport Proximity", "Palm Rest", "Palm Rest Actuator", \ - "Battery Max", "Battery Sensor 1", "Battery Sensor 2", "SSD A", "SSD B", \ - "CPU Core 1", "CPU Core 2", "CPU Core 3", "CPU Core 4", "CPU PECI Die", \ - "Intel GPU", "Platform Controller Hub PECI", "CPU System Agent Core", "CPU VCore", "DC In", \ - "Pbus", "Ambient Light", "Leftside", "Rightside", "CPU Package Core", \ - "CPU Package GPU", "CPU Package Total", "System Total", "DC In" } - -#define ASMC_MBP131_TEMPS { "TB0T", "TB1T", "TB2T", "TC0F", \ - "TC0P", "TC1C", "TC2C", "TCGC", \ - "TCSA", "TCXC", "Th1H", "TM0P", \ - "TPCD", "Ts0P", "Ts0S", "TaLC", \ - "Ts1P", NULL } - -#define ASMC_MBP131_TEMPNAMES { "battery", "battery_1", "battery_2", "cpu_die_peci", \ - "cpu_proximity", "cpu_core_1", "cpu_core_2", "intel_gpu", \ - "cpu_sys_agent", "cpu_core_peci", "right_fin_stack", "memory_proximity", \ - "platform_ctrl_hub", "trackpad", "bottom_skin", "air_flow", \ - "trackpad_act" } - -#define ASMC_MBP131_TEMPDESCS { "Battery", "Battery Sensor 1", "Battery Sensor 2", "CPU Die (PECI)", \ - "CPU Proximity", "CPU Core 1", "CPU Core 2", "Intel GPU", \ - "CPU System Agent Core (PECI)", "CPU Core (PECI)", "Right Fin Stack", "DDR3 Proximity", \ - "Platform Controller Hub Die", "Trackpad", "Bottom Skin", "Air Flow", \ - "Trackpad Actuator" } - -#define ASMC_MM_TEMPS { "TN0P", "TN1P", NULL } -#define ASMC_MM_TEMPNAMES { "northbridge1", "northbridge2" } -#define ASMC_MM_TEMPDESCS { "Northbridge Point 1", \ - "Northbridge Point 2" } - -#define ASMC_MM21_TEMPS { "TA0P", "TC0D", \ - "TC0H", "TC0P", \ - "TC1P", "TN0P", \ - "TN1P", NULL } - -#define ASMC_MM21_TEMPNAMES { "ambient_air", "cpu_die", \ - "cpu_heatsink", "cpu_proximity1", \ - "cpu_proximity2", "northbridge_proximity1", \ - "northbridge_proximity2", } - -#define ASMC_MM21_TEMPDESCS { "Ambient Air Temperature" \ - "CPU Die Core Temperature", \ - "CPU Heatsink Temperature", \ - "CPU Proximity 1 Temperature", \ - "CPU Proximity 2 Temperature", \ - "Northbridge Proximity 1 Temperature", \ - "Northbridge Proximity 2 Temperature", } - -#define ASMC_MM31_TEMPS { "TC0D", "TC0H", \ - "TC0P", "TH0P", \ - "TN0D", "TN0P", \ - "TW0P", NULL } - -#define ASMC_MM31_TEMPNAMES { "cpu0_die", "cpu0_heatsink", \ - "cpu0_proximity", "hdd_bay", \ - "northbridge_die", \ - "northbridge_proximity", \ - "wireless_proximity", } - -#define ASMC_MM31_TEMPDESCS { "CPU0 Die Core Temperature", \ - "CPU0 Heatsink Temperature", \ - "CPU0 Proximity Temperature", \ - "HDD Bay Temperature", \ - "Northbridge Die Core Temperature", \ - "Northbridge Proximity Temperature", \ - "Wireless Module Proximity Temperature", } - -#define ASMC_MM41_TEMPS { "TA0P", "TC0D", "TC0G", "TC0H", "TC0P", \ - "TC0p", "TCPG", "TH0G", "TH0P", "TH0p", \ - "TM0G", "TM0P", "TM0p", "TN0D", "TN0G", \ - "TN0P", "TN0p", "TN1D", "TN1E", "TN1F", \ - "TN1G", "TN1S", "TNPG", "TO0P", "TO0p", \ - "TW0P", "Tm0P", "Tp0C", NULL } - -#define ASMC_MM41_TEMPNAMES { "TA0P", "TC0D", "TC0G", "TC0H", "TC0P", \ - "TC0p", "TCPG", "TH0G", "TH0P", "TH0p", \ - "TM0G", "TM0P", "TM0p", "TN0D", "TN0G", \ - "TN0P", "TN0p", "TN1D", "TN1E", "TN1F", \ - "TN1G", "TN1S", "TNPG", "TO0P", "TO0p", \ - "TW0P", "Tm0P", "Tp0C", NULL } - -#define ASMC_MM41_TEMPDESCS { "TA0P", "TC0D", "TC0G", "TC0H", "TC0P", \ - "TC0p", "TCPG", "TH0G", "TH0P", "TH0p", \ - "TM0G", "TM0P", "TM0p", "TN0D", "TN0G", \ - "TN0P", "TN0p", "TN1D", "TN1E", "TN1F", \ - "TN1G", "TN1S", "TNPG", "TO0P", "TO0p", \ - "TW0P", "Tm0P", "Tp0C", NULL } - -#define ASMC_MM52_TEMPS { "TA0P", "TA1P", \ - "TC0D", "TC0P", \ - "TG0D", "TG1D", \ - "TG0P", "TG0M", \ - "TI0P", \ - "TM0S", "TMBS", \ - "TM0P", "TP0P", \ - "TPCD", "Tp0C", \ - "TW0P", NULL } - -#define ASMC_MM52_TEMPNAMES { "ambient_air_proximity", "ambient_cpu_pch_wireless_dimm", \ - "cpu_die", "cpu_proximity", \ - "gpu_diode1", "gpu_diode2", \ - "gpu_proximity", "gpu_integrated_switcher", \ - "thunderbolt_proximity", \ - "memory_slot1", "memory_slot2", \ - "memory_proximity", "pch_controller_proximity", \ - "pch_controller_die", "pwr_supply", \ - "wireless_proximity", } - -#define ASMC_MM52_TEMPDESCS { "Ambient Air Proximity Temperature", \ - "Combo Ambient CPU PCH Wireless DIMM Temperature", \ - "CPU Die Temperature", "CPU Proximity Temperature", \ - "GPU Diode 1 Temperature" , "GPU Diode 2 Temperature", \ - "GPU Proximity Temperature", \ - "Integrated Graphics/GPU Switcher Temperature", \ - "Thunderbolt Proximity Temperature", \ - "Memory Slot 1 Temperature", \ - "Memory Slot 2 Temperature", \ - "Memory Slots Proximity Temperature", \ - "Platform Controller Hub Proximity Temperature", \ - "Platform Controller Hub Die Temperature", \ - "Power Supply Temperature", \ - "Wireless Module Proximity Temperature", } - -#define ASMC_MM61_TEMPS { "TA0P", "TA1P", \ - "TC0D", "TC0G", "TC0P", "TCPG", \ - "TI0P", \ - "TM0S", "TMBS", "TM0P", \ - "TP0P", "TPCD", \ - "Tp0C", \ - "TW0P", NULL } - -#define ASMC_MM61_TEMPNAMES { "ambient_air_proximity", "ambient_cpu_pch_wireless_dimm", \ - "cpu_die", "TC0G", "cpu_proximity", "TCPG", \ - "thunderbolt_proximity", \ - "memory_slot1", "memory_slot2", "memory_proximity", \ - "pch_controller_proximity", "pch_controller_die", \ - "pwr_supply", \ - "wireless_proximity", NULL } - -#define ASMC_MM61_TEMPDESCS { "Ambient Air Proximity Temperature", \ - "Combo Ambient CPU PCH Wireless DIMM Temperature", \ - "CPU Die Temperature", \ - NULL, \ - "CPU Proximity Temperature", \ - NULL, \ - "Thunderbolt Proximity Temperature", \ - "Memory Slot 1 Temperature", \ - "Memory Slot 2 Temperature", \ - "Memory Slots Proximity Temperature", \ - "Platform Controller Hub Proximity Temperature", \ - "Platform Controller Hub Die Temperature", \ - "Power Supply Temperature", \ - "Wireless Module Proximity Temperature", NULL } - -#define ASMC_MM62_TEMPS { "TA0P", "TA1P", \ - "TC0D", "TC0G", "TC0P", "TCPG", \ - "TI0P", \ - "TM0S", "TMBS", "TM0P", \ - "TP0P", "TPCD", \ - "Tp0C", \ - "TW0P", NULL } - -#define ASMC_MM62_TEMPNAMES { "ambient_air_proximity", "ambient_cpu_pch_wireless_dimm", \ - "cpu_die", "TC0G", "cpu_proximity", "TCPG", \ - "thunderbolt_proximity", \ - "memory_slot1", "memory_slot2", "memory_proximity", \ - "pch_controller_proximity", "pch_controller_die", \ - "pwr_supply", \ - "wireless_proximity", NULL } - -#define ASMC_MM62_TEMPDESCS { "Ambient Air Proximity Temperature", \ - "Combo Ambient CPU PCH Wireless DIMM Temperature", \ - "CPU Die Temperature", \ - NULL, \ - "CPU Proximity Temperature", \ - NULL, \ - "Thunderbolt Proximity Temperature", \ - "Memory Slot 1 Temperature", \ - "Memory Slot 2 Temperature", \ - "Memory Slots Proximity Temperature", \ - "Platform Controller Hub Proximity Temperature", \ - "Platform Controller Hub Die Temperature", \ - "Power Supply Temperature", \ - "Wireless Module Proximity Temperature", NULL } - -#define ASMC_MM71_TEMPS { "TA0p", "TA1p", \ - "TA2p", "TC0c", \ - "TC0p", "TC1c", \ - "TCGc", "TCSc", \ - "TCXC", "TCXR", \ - "TM0p", "TPCd", \ - "TW0p", "Te0T", \ - "Tm0P", NULL } - -#define ASMC_MM71_TEMPNAMES { "ambient_air1", "ambient_air2", \ - "ambient_air3", "cpu_core1_peci", \ - "cpu_proximity", "cpu_core2_peci", \ - "intel_gpu", "cpu_sa_core_peci", \ - "cpu_core", "cpu_peci_dts", \ - "memory_proximity", "pch_controller_die", \ - "wireless_proximity", "thunderbolt_diode", \ - "logic_board", } - -#define ASMC_MM71_TEMPDESCS { "Ambient Air Temperature 1", \ - "Ambient Air Temperature 2", \ - "Ambient Air Temperature 3", \ - "CPU Core 1 PECI Temperature", "CPU Proximity Temperature", \ - "CPU Core 2 PECI Temperature", "Intel GPU Temperature", \ - "CPU System Agent Core PECI Temperature", \ - "CPU Core Temperature", "CPU PECI DTS Temperature", \ - "Memory Proximity Temperature", \ - "Platform Controller Hub Die Temperature", \ - "Wireless Module Proximity Temperature", \ - "Thunderbolt Diode Temperature", \ - "Logic Board temperature", } - -#define ASMC_MP1_TEMPS { "TA0P", \ - "TCAH", "TCBH", \ - "TC0P", "TC0C", "TC1C", \ - "TC2C", "TC3C", "THTG", \ - "TH0P", "TH1P", \ - "TH2P", "TH3P", \ - "TM0P", "TM1P", "TM2P", \ - "TM8P", "TM9P", "TMAP", \ - "TM0S", "TM1S", "TM2P", "TM3S", \ - "TM8S", "TM9S", "TMAS", "TMBS", \ - "TN0H", "TS0C", \ - "Tp0C", "Tp1C", "Tv0S", "Tv1S", NULL } - -#define ASMC_MP1_TEMPNAMES { "ambient", \ - "cpu_a_heatsink", "cpu_b_heatsink", \ - "cpu_a_proximity", "cpu_core0", "cpu_core1", \ - "cpu_core2", "cpu_core3", "THTG", \ - "hdd_bay0", "hdd_bay1", \ - "hdd_bay2", "hdd_bay3", \ - "memory_card_a_proximity0", \ - "memory_card_a_proximity1", \ - "memory_card_a_proximity2", \ - "memory_card_b_proximity0", \ - "memory_card_b_proximity1", \ - "memory_card_b_proximity2", \ - "memory_card_a_slot0", \ - "memory_card_a_slot1", \ - "memory_card_a_slot2", \ - "memory_card_a_slot3", \ - "memory_card_b_slot0", \ - "memory_card_b_slot1", \ - "memory_card_b_slot2", \ - "memory_card_b_slot3", \ - "mch_heatsink", "expansion_slots", \ - "power_supply_loc0", "power_supply_loc1", \ - "Tv0S", "Tv1S", } - -#define ASMC_MP1_TEMPDESCS { "Ambient Air", \ - "CPU A Heatsink", "CPU B Heatsink", \ - "CPU A Proximity", \ - "CPU Core 1", "CPU Core 2", \ - "CPU Core 3", "CPU Core 4", "THTG", \ - "Hard Drive Bay 1", "Hard Drive Bay 2", \ - "Hard Drive Bay 3", "Hard Drive Bay 4", \ - "Memory Riser A, Proximity 1", \ - "Memory Riser A, Proximity 2", \ - "Memory Riser A, Proximity 3", \ - "Memory Riser B, Proximity 1", \ - "Memory Riser B, Proximity 2", \ - "Memory Riser B, Proximity 3", \ - "Memory Riser A, Slot 1", \ - "Memory Riser A, Slot 2", \ - "Memory Riser A, Slot 3", \ - "Memory Riser A, Slot 4", \ - "Memory Riser B, Slot 1", \ - "Memory Riser B, Slot 2", \ - "Memory Riser B, Slot 3", \ - "Memory Riser B, Slot 4", \ - "MCH Heatsink", "Expansion Slots", \ - "Power Supply, Location 1", \ - "Power Supply, Location 2", \ - "Tv0S", "Tv1S", } - -#define ASMC_MP31_TEMPS { "TA0P", \ - "TC0C", "TC0D", "TC0P", \ - "TC1C", "TC1D", \ - "TC2C", "TC2D", \ - "TC3C", "TC3D", \ - "TCAG", "TCAH", "TCBG", "TCBH", \ - "TH0P", "TH1P", "TH2P", "TH3P", \ - "TM0P", "TM0S", "TM1P", "TM1S", \ - "TM2P", "TM2S", "TM3S", \ - "TM8P", "TM8S", "TM9P", "TM9S", \ - "TMAP", "TMAS", "TMBS", \ - "TN0C", "TN0D", "TN0H", \ - "TS0C", \ - "Tp0C", "Tp1C", \ - "Tv0S", "Tv1S", NULL } - -#define ASMC_MP31_TEMPNAMES { "ambient", \ - "cpu_core0", "cpu_diode0", "cpu_a_proximity", \ - "cpu_core1", "cpu_diode1", \ - "cpu_core2", "cpu_diode2", \ - "cpu_core3", "cpu_diode3", \ - "cpu_a_pkg", "cpu_a_heatsink", \ - "cpu_b_pkg", "cpu_b_heatsink", \ - "hdd_bay0", "hdd_bay1", \ - "hdd_bay2", "hdd_bay3", \ - "mem_riser_a_prox0", "mem_riser_a_slot0", \ - "mem_riser_a_prox1", "mem_riser_a_slot1", \ - "mem_riser_a_prox2", "mem_riser_a_slot2", \ - "mem_riser_a_slot3", \ - "mem_riser_b_prox0", "mem_riser_b_slot0", \ - "mem_riser_b_prox1", "mem_riser_b_slot1", \ - "mem_riser_b_prox2", "mem_riser_b_slot2", \ - "mem_riser_b_slot3", \ - "northbridge_core", "northbridge_diode", \ - "northbridge_heatsink", \ - "expansion_slots", \ - "power_supply0", "power_supply1", \ - "vrm0", "vrm1", } - -#define ASMC_MP31_TEMPDESCS { "Ambient Air", \ - "CPU Core 1", "CPU Diode 1", \ - "CPU A Proximity", \ - "CPU Core 2", "CPU Diode 2", \ - "CPU Core 3", "CPU Diode 3", \ - "CPU Core 4", "CPU Diode 4", \ - "CPU A Package", "CPU A Heatsink", \ - "CPU B Package", "CPU B Heatsink", \ - "Hard Drive Bay 1", "Hard Drive Bay 2", \ - "Hard Drive Bay 3", "Hard Drive Bay 4", \ - "Memory Riser A, Proximity 1", \ - "Memory Riser A, Slot 1", \ - "Memory Riser A, Proximity 2", \ - "Memory Riser A, Slot 2", \ - "Memory Riser A, Proximity 3", \ - "Memory Riser A, Slot 3", \ - "Memory Riser A, Slot 4", \ - "Memory Riser B, Proximity 1", \ - "Memory Riser B, Slot 1", \ - "Memory Riser B, Proximity 2", \ - "Memory Riser B, Slot 2", \ - "Memory Riser B, Proximity 3", \ - "Memory Riser B, Slot 3", \ - "Memory Riser B, Slot 4", \ - "Northbridge Core", "Northbridge Diode", \ - "Northbridge Heatsink", \ - "Expansion Slots", \ - "Power Supply 1", "Power Supply 2", \ - "VRM 1", "VRM 2", } - -#define ASMC_MP2_TEMPS { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", \ - "TC0C", "TC0D", "TC0P", "TC1C", "TC1D", \ - "TC2C", "TC2D", "TC3C", "TC3D", "THTG", \ - "TH0P", "TH1P", "TH2P", "TH3P", "TMAP", \ - "TMAS", "TMBS", "TM0P", "TM0S", "TM1P", \ - "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", \ - "TM8S", "TM9P", "TM9S", "TN0H", "TS0C", \ - NULL } - -#define ASMC_MP2_TEMPNAMES { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", \ - "TC0C", "TC0D", "TC0P", "TC1C", "TC1D", \ - "TC2C", "TC2D", "TC3C", "TC3D", "THTG", \ - "TH0P", "TH1P", "TH2P", "TH3P", "TMAP", \ - "TMAS", "TMBS", "TM0P", "TM0S", "TM1P", \ - "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", \ - "TM8S", "TM9P", "TM9S", "TN0H", "TS0C", } - -#define ASMC_MP2_TEMPDESCS { "TA0P", "TCAG", "TCAH", "TCBG", "TCBH", \ - "TC0C", "TC0D", "TC0P", "TC1C", "TC1D", \ - "TC2C", "TC2D", "TC3C", "TC3D", "THTG", \ - "TH0P", "TH1P", "TH2P", "TH3P", "TMAP", \ - "TMAS", "TMBS", "TM0P", "TM0S", "TM1P", \ - "TM1S", "TM2P", "TM2S", "TM3S", "TM8P", \ - "TM8S", "TM9P", "TM9S", "TN0H", "TS0C", } - -#define ASMC_MP5_TEMPS { "TA0P", "TCAC", "TCAD", "TCAG", "TCAH", \ - "TCAS", "TCBC", "TCBD", "TCBG", "TCBH", \ - "TCBS", "TH1F", "TH1P", "TH1V", "TH2F", \ - "TH2P", "TH2V", "TH3F", "TH3P", "TH3V", \ - "TH4F", "TH4P", "TH4V", "THPS", "THTG", \ - "TM1P", "TM2P", "TM2V", "TM3P", "TM3V", \ - "TM4P", "TM5P", "TM6P", "TM6V", "TM7P", \ - "TM7V", "TM8P", "TM8V", "TM9V", "TMA1", \ - "TMA2", "TMA3", "TMA4", "TMB1", "TMB2", \ - "TMB3", "TMB4", "TMHS", "TMLS", "TMPS", \ - "TMPV", "TMTG", "TN0D", "TN0H", "TNTG", \ - "Te1F", "Te1P", "Te1S", "Te2F", "Te2S", \ - "Te3F", "Te3S", "Te4F", "Te4S", "Te5F", \ - "Te5S", "TeGG", "TeGP", "TeRG", "TeRP", \ - "TeRV", "Tp0C", "Tp1C", "TpPS", "TpTG", \ - NULL } - -#define ASMC_MP5_TEMPNAMES { "ambient", "TCAC", "TCAD", "TCAG", "TCAH", \ - "TCAS", "TCBC", "TCBD", "TCBG", "TCBH", \ - "TCBS", "TH1F", "TH1P", "TH1V", "TH2F", \ - "TH2P", "TH2V", "TH3F", "TH3P", "TH3V", \ - "TH4F", "TH4P", "TH4V", "THPS", "THTG", \ - "TM1P", "TM2P", "TM2V", "TM3P", "TM3V", \ - "TM4P", "TM5P", "TM6P", "TM6V", "TM7P", \ - "TM7V", "TM8P", "TM8V", "TM9V", "ram_a1", \ - "ram_a2", "ram_a3", "ram_a4", "ram_b1", "ram_b2", \ - "ram_b3", "ram_b4", "TMHS", "TMLS", "TMPS", \ - "TMPV", "TMTG", "TN0D", "TN0H", "TNTG", \ - "Te1F", "Te1P", "Te1S", "Te2F", "Te2S", \ - "Te3F", "Te3S", "Te4F", "Te4S", "Te5F", \ - "Te5S", "TeGG", "TeGP", "TeRG", "TeRP", \ - "TeRV", "Tp0C", "Tp1C", "TpPS", "TpTG", } - -#define ASMC_MP5_TEMPDESCS { "TA0P", "TCAC", "TCAD", "TCAG", "TCAH", \ - "TCAS", "TCBC", "TCBD", "TCBG", "TCBH", \ - "TCBS", "TH1F", "TH1P", "TH1V", "TH2F", \ - "TH2P", "TH2V", "TH3F", "TH3P", "TH3V", \ - "TH4F", "TH4P", "TH4V", "THPS", "THTG", \ - "TM1P", "TM2P", "TM2V", "TM3P", "TM3V", \ - "TM4P", "TM5P", "TM6P", "TM6V", "TM7P", \ - "TM7V", "TM8P", "TM8V", "TM9V", "TMA1", \ - "TMA2", "TMA3", "TMA4", "TMB1", "TMB2", \ - "TMB3", "TMB4", "TMHS", "TMLS", "TMPS", \ - "TMPV", "TMTG", "TN0D", "TN0H", "TNTG", \ - "Te1F", "Te1P", "Te1S", "Te2F", "Te2S", \ - "Te3F", "Te3S", "Te4F", "Te4S", "Te5F", \ - "Te5S", "TeGG", "TeGP", "TeRG", "TeRP", \ - "TeRV", "Tp0C", "Tp1C", "TpPS", "TpTG", } - -#define ASMC_MP6_TEMPS { "TA0P", "TA1P", "TC0P", "TG0D", "TG0P", \ - "TG1D", "TG1P", "TM0P", "TM1P", NULL } - -#define ASMC_MP6_TEMPNAMES { "ambient_air_1", "ambient_air_2", \ - "cpu_proximity", "gpu_diode_1", \ - "gpu_proximity_1", "gpu_diode_2", \ - "gpu_proximity_2", "mem_proximity_1", \ - "mem_proximity_2" } - -#define ASMC_MP6_TEMPDESCS { "Ambient Air 1", "Ambient Air 2", \ - "CPU Proximity", "GPU Diode 1", \ - "GPU Proximity 1", "GPU Diode 2", \ - "GPU Proximity 2", "Memory Bank A", \ - "Memory Bank B" } - -#define ASMC_MBA_TEMPS { "TB0T", NULL } -#define ASMC_MBA_TEMPNAMES { "enclosure" } -#define ASMC_MBA_TEMPDESCS { "Enclosure Bottom" } - -#define ASMC_MBA3_TEMPS { "TB0T", "TB1T", "TB2T", \ - "TC0D", "TC0E", "TC0P", NULL } - -#define ASMC_MBA3_TEMPNAMES { "enclosure", "TB1T", "TB2T", \ - "TC0D", "TC0E", "TC0P" } - -#define ASMC_MBA3_TEMPDESCS { "Enclosure Bottom", "TB1T", "TB2T", \ - "TC0D", "TC0E", "TC0P" } - -#define ASMC_MBA4_TEMPS { "TB0T", "TB1T", "TB2T", "TC0C", \ - "TC0D", "TC0E", "TC0F", "TC0P", \ - "TC1C", "TC2C", "TCGC", "TCSA", \ - "TH0F", "TH0J", "TH0O", "TH0o", \ - "TM0P", "TPCD", "Ta0P", "Th1H", \ - "Tm0P", "Tm1P", "Ts0P", "Ts0S", \ - NULL } - -#define ASMC_MBA4_TEMPNAMES { "TB0T", "TB1T", "TB2T", "TC0C", \ - "TC0D", "TC0E", "TC0F", "TC0P", \ - "TC1C", "TC2C", "TCGC", "TCSA", \ - "TH0F", "TH0J", "TH0O", "TH0o", \ - "TM0P", "TPCD", "Ta0P", "Th1H", \ - "Tm0P", "Tm1P", "Ts0P", "Ts0S", \ - NULL } - -#define ASMC_MBA4_TEMPDESCS { "TB0T", "TB1T", "TB2T", "TC0C", \ - "TC0D", "TC0E", "TC0F", "TC0P", \ - "TC1C", "TC2C", "TCGC", "TCSA", \ - "TH0F", "TH0J", "TH0O", "TH0o", \ - "TM0P", "TPCD", "Ta0P", "Th1H", \ - "Tm0P", "Tm1P", "Ts0P", "Ts0S", \ - NULL } - -#define ASMC_MBA5_TEMPS { "TB0T", "TB1T", "TB2T", "TC0C", \ - "TC0D", "TC0E", "TC0F", "TC0P", \ - "TC1C", "TC2C", "TCGC", "TCSA", \ - "TCXC", "THSP", "TM0P", "TPCD", \ - "Ta0P", "Th1H", "Tm0P", "Tm1P", \ - "Ts0P", "Ts0S", NULL } - -#define ASMC_MBA5_TEMPNAMES { "enclosure1", "enclosure2", "enclosure3", "TC0C", \ - "cpudiode", "cputemp1", "cputemp2", "cpuproximity", \ - "cpucore1", "cpucore2", "cpupeci", "pecisa", \ - "TCXC", "THSP", "memorybank", "pchdie", \ - "Ta0P", "heatpipe", "mainboardproximity1", "mainboardproximity2", \ - "palmrest", "memoryproximity" } - -#define ASMC_MBA5_TEMPDESCS { "Enclosure Bottom 1", "Enclosure Bottom 2", "Enclosure Bottom 3", "TC0C",\ - "CPU Diode", "CPU Temp 1", "CPU Temp 2", "CPU Proximity", \ - "CPU Core 1", "CPU Core 2", "CPU Peci Core", "PECI SA", \ - "TCXC", "THSP", "Memory Bank A", "PCH Die", \ - "Ta0P", "Heatpipe", "Mainboard Proximity 1", "Mainboard Proximity 2", \ - "Palm Rest", "Memory Proximity" } - -/* - * TODO: validate the temp zones for MBA 6.x ! - */ -#define ASMC_MBA6_TEMPS { "TB0T", "TB1T", "TB2T", \ - "TC0E", "TC0F", "TC0P", \ - "TC1C", "TC2C", "TCGC", "TCSA", \ - "TCXC", "THSP", "TM0P", "TPCD", \ - "Ta0P", "Th1H", "Tm0P", \ - "Ts0P", "Ts0S", NULL } - -#define ASMC_MBA6_TEMPNAMES { "enclosure1", "enclosure2", "enclosure3", \ - "cputemp1", "cputemp2", "cpuproximity", \ - "cpucore1", "cpucore2", "cpupeci", "pecisa", \ - "TCXC", "THSP", "memorybank", "pchdie", \ - "Ta0P", "heatpipe", "mainboardproximity1", \ - "palmrest", "memoryproximity" } - -#define ASMC_MBA6_TEMPDESCS { "Enclosure Bottom 1", "Enclosure Bottom 2", "Enclosure Bottom 3", \ - "CPU Temp 1", "CPU Temp 2", "CPU Proximity", \ - "CPU Core 1", "CPU Core 2", "CPU Peci Core", "PECI SA", \ - "TCXC", "THSP", "Memory Bank A", "PCH Die", \ - "Ta0P", "Heatpipe", "Mainboard Proximity 1", \ - "Palm Rest", "Memory Proximity" } - - -#define ASMC_MBA7_TEMPS { "TB0T", "TB1T", "TB2T", \ - "TC0E", "TC0F", "TC0P", \ - "TC1C", "TC2C", \ - "TCGC", "TCSA", "TCXC", \ - "THSP", "TM0P", "TPCD", \ - "TW0P" "Ta0P", "Th1H", \ - "Tm0P", "Ts0P", "Ts0S", NULL } - -#define ASMC_MBA7_TEMPNAMES { "enclosure1", "enclosure2", "enclosure3", \ - "cputemp1", "cputemp2", "cpuproximity", \ - "cpucore1", "cpucore2", \ - "pecigpu", "pecisa", "pecicpu", \ - "thunderboltproximity", "memorybank", "pchdie", \ - "wirelessproximity", "airflowproximity", "heatpipe", \ - "mainboardproximity", "palmrest", "memoryproximity" } - -#define ASMC_MBA7_TEMPDESCS { "Enclosure Bottom 1", "Enclosure Bottom 2", "Enclosure Bottom 3", \ - "CPU Temp 1", "CPU Temp 2", "CPU Proximity", \ - "CPU Core 1", "CPU Core 2", \ - "PECI GPU", "PECI SA", "PECI CPU", \ - "Thunderbolt Proximity", "Memory Bank A", "PCH Die", \ - "Wireless Proximity", "Airflow Proxmity", "Heatpipe", \ - "Mainboard Proximity", "Palm Rest", "Memory Proximity" } diff --git a/sys/dev/dpaa/bman.c b/sys/dev/dpaa/bman.c index c275d2335eb8..3d1052f9ed9f 100644 --- a/sys/dev/dpaa/bman.c +++ b/sys/dev/dpaa/bman.c @@ -1,27 +1,7 @@ -/*- - * Copyright (c) 2011-2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. +/* + * Copyright (c) 2026 Justin Hibbits * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * SPDX-License-Identifier: BSD-2-Clause */ #include <sys/param.h> @@ -29,6 +9,7 @@ #include <sys/kernel.h> #include <sys/bus.h> #include <sys/lock.h> +#include <sys/malloc.h> #include <sys/module.h> #include <sys/mutex.h> #include <sys/proc.h> @@ -36,63 +17,161 @@ #include <sys/rman.h> #include <sys/sched.h> +#include <machine/bus.h> #include <machine/tlb.h> #include "bman.h" +#include "dpaa_common.h" +#include "bman_var.h" + +#define BMAN_POOL_SWDET(n) (0x000 + 4 * (n)) +#define BMAN_POOL_HWDET(n) (0x100 + 4 * (n)) +#define BMAN_POOL_SWDXT(n) (0x200 + 4 * (n)) +#define BMAN_POOL_HWDXT(n) (0x300 + 4 * (n)) +#define FBPR_FP_LWIT 0x804 +#define BMAN_IP_REV_1 0x0bf8 +#define IP_MAJ_S 8 +#define IP_MAJ_M 0x0000ff00 +#define IP_MIN_M 0x000000ff +#define BMAN_IP_REV_2 0x0bfc +#define BMAN_FBPR_BARE 0x0c00 +#define BMAN_FBPR_BAR 0x0c04 +#define BMAN_FBPR_AR 0x0c10 +#define BMAN_LIODNR 0x0d08 + +#define BMAN_POOL_CONTENT(n) (0x0600 + 4 * (n)) +#define BMAN_ECSR 0x0a00 +#define BMAN_ECIR 0x0a04 +#define ECIR_PORTAL(r) (((r) >> 24) & 0x0f) +#define ECIR_VERB(r) (((r) >> 16) & 0x07) +#define ECIR_R 0x00080000 +#define ECIR_POOL(r) ((r) & 0x3f) +#define BMAN_CECR 0x0a34 /* Corruption Error Capture Register */ +#define BMAN_CEAR 0x0a38 /* Corruption Error Address Register */ +#define BMAN_AECR 0x0a34 /* Acces Error Capture Register */ +#define BMAN_AEAR 0x0a38 /* Acces Error Address Register */ +#define BMAN_ERR_ISR 0x0e00 +#define BMAN_ERR_IER 0x0e04 +#define BMAN_ERR_ISDR 0x0e08 +#define ERR_EMAI 0x00000040 +#define ERR_EMCI 0x00000020 +#define ERR_IVCI 0x00000010 +#define ERR_FLWI 0x00000008 +#define ERR_MBEI 0x00000004 +#define ERR_SBEI 0x00000002 +#define ERR_BSCN 0x00000001 + +static MALLOC_DEFINE(M_BMAN, "bman", "DPAA Buffer Manager structures"); static struct bman_softc *bman_sc; -extern t_Handle bman_portal_setup(struct bman_softc *bsc); +static void +bman_isr(void *arg) +{ + struct bman_softc *sc = arg; + uint32_t ier, isr, isr_bit; + uint32_t reg; + + ier = bus_read_4(sc->sc_rres, BMAN_ERR_IER); + isr = bus_read_4(sc->sc_rres, BMAN_ERR_ISR); + + isr_bit = (isr & ier); + if (isr_bit == 0) + goto end; + + if (isr_bit & ERR_EMAI) { + device_printf(sc->sc_dev, "External memory access error\n"); + reg = bus_read_4(sc->sc_rres, BMAN_AECR); + if (reg <= 63) + device_printf(sc->sc_dev, " pool %d\n", reg); + else + device_printf(sc->sc_dev, " FBPR free list\n"); + reg = bus_read_4(sc->sc_rres, BMAN_AEAR); + device_printf(sc->sc_dev, " offset: %#x\n", reg); + } + + if (isr_bit & ERR_EMCI) { + device_printf(sc->sc_dev, "External memory corruption error\n"); + reg = bus_read_4(sc->sc_rres, BMAN_CECR); + if (reg <= 63) + device_printf(sc->sc_dev, " pool %d\n", reg); + else + device_printf(sc->sc_dev, " FBPR free list\n"); + reg = bus_read_4(sc->sc_rres, BMAN_CEAR); + device_printf(sc->sc_dev, " offset: %#x\n", reg); + } + if (isr_bit & ERR_IVCI) { + reg = bus_read_4(sc->sc_rres, BMAN_ECIR); + device_printf(sc->sc_dev, "Invalid verb command\n"); + device_printf(sc->sc_dev, "Portal: %d, ring: %s\n", + ECIR_POOL(reg), (reg & ECIR_R) ? "RCR" : "Command"); + device_printf(sc->sc_dev, "verb: 0x%02x, pool: %d\n", + ECIR_VERB(reg), ECIR_POOL(reg)); + } + if (isr_bit & (ERR_MBEI | ERR_SBEI)) { + if (isr_bit & ERR_MBEI) + device_printf(sc->sc_dev, "Multi-bit ECC error\n"); + if (isr_bit & ERR_MBEI) + device_printf(sc->sc_dev, "Single-bit ECC error\n"); + /* TODO: Add more error details for ECC errors. */ + } + +end: + bus_write_4(sc->sc_rres, BMAN_ERR_ISR, isr); +} static void -bman_exception(t_Handle h_App, e_BmExceptions exception) +bman_get_version(struct bman_softc *sc) { - struct bman_softc *sc; - const char *message; + uint32_t reg = bus_read_4(sc->sc_rres, BMAN_IP_REV_1); - sc = h_App; + sc->sc_major = (reg & IP_MAJ_M) >> IP_MAJ_S; + sc->sc_minor = (reg & IP_MIN_M); +} - switch (exception) { - case e_BM_EX_INVALID_COMMAND: - message = "Invalid Command Verb"; - break; - case e_BM_EX_FBPR_THRESHOLD: - message = "FBPR pool exhaused. Consider increasing " - "BMAN_MAX_BUFFERS"; - break; - case e_BM_EX_SINGLE_ECC: - message = "Single bit ECC error"; - break; - case e_BM_EX_MULTI_ECC: - message = "Multi bit ECC error"; - break; - default: - message = "Unknown error"; +static int +bman_set_memory(struct bman_softc *sc, vm_paddr_t pa, vm_size_t size) +{ + vm_paddr_t bar_pa; + if ((pa & (size - 1)) != 0 || (size & (size - 1)) != 0) { + device_printf(sc->sc_dev, + "invalid memory configuration: pa: %#jx, size: %#jx\n", + (uintmax_t)pa, (uintmax_t)size); + return (ENXIO); } + bar_pa = bus_read_4(sc->sc_rres, BMAN_FBPR_BARE); + bar_pa <<= 32; + bar_pa |= bus_read_4(sc->sc_rres, BMAN_FBPR_BAR); + if (bar_pa != 0 && bar_pa != pa) { + device_printf(sc->sc_dev, + "attempted to reinitialize BMan with different BAR\n"); + return (ENOMEM); + } else if (bar_pa == pa) + return (0); + + bus_write_4(sc->sc_rres, BMAN_FBPR_BARE, pa >> 32); + bus_write_4(sc->sc_rres, BMAN_FBPR_BAR, pa & 0xffffffff); + bus_write_4(sc->sc_rres, BMAN_FBPR_AR, ilog2(size) - 1); - device_printf(sc->sc_dev, "BMAN Exception: %s.\n", message); + return (0); } int bman_attach(device_t dev) { struct bman_softc *sc; - t_BmRevisionInfo rev; - t_Error error; - t_BmParam bp; + vm_paddr_t bp_pa; + size_t bp_size; + int bp_count; sc = device_get_softc(dev); sc->sc_dev = dev; bman_sc = sc; - /* Check if MallocSmart allocator is ready */ - if (XX_MallocSmartInit() != E_OK) - return (ENXIO); - /* Allocate resources */ sc->sc_rrid = 0; - sc->sc_rres = bus_alloc_resource_anywhere(dev, SYS_RES_MEMORY, - &sc->sc_rrid, BMAN_CCSR_SIZE, RF_ACTIVE); + sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + sc->sc_rrid, RF_ACTIVE); if (sc->sc_rres == NULL) return (ENXIO); @@ -102,36 +181,33 @@ bman_attach(device_t dev) if (sc->sc_ires == NULL) goto err; - /* Initialize BMAN */ - memset(&bp, 0, sizeof(bp)); - bp.guestId = NCSW_MASTER_ID; - bp.baseAddress = rman_get_bushandle(sc->sc_rres); - bp.totalNumOfBuffers = BMAN_MAX_BUFFERS; - bp.f_Exception = bman_exception; - bp.h_App = sc; - bp.errIrq = (uintptr_t)sc->sc_ires; - bp.partBpidBase = 0; - bp.partNumOfPools = BM_MAX_NUM_OF_POOLS; + bman_get_version(sc); + if (sc->sc_major == 2 && sc->sc_minor == 0) + bp_count = BMAN_MAX_POOLS_1023; + else + bp_count = BMAN_MAX_POOLS; - sc->sc_bh = BM_Config(&bp); - if (sc->sc_bh == NULL) - goto err; + /* TODO: LIODN */ + bus_write_4(sc->sc_rres, BMAN_LIODNR, 0); - /* Warn if there is less than 5% free FPBR's in pool */ - error = BM_ConfigFbprThreshold(sc->sc_bh, (BMAN_MAX_BUFFERS / 8) / 20); - if (error != E_OK) - goto err; + sc->sc_vmem = vmem_create("BMan Pools", 0, bp_count, 1, 0, M_WAITOK); - error = BM_Init(sc->sc_bh); - if (error != E_OK) - goto err; + /* Pool is reserved memory, so no need to track it ourselves. */ + dpaa_map_private_memory(dev, 0, "fsl,bman-fbpr", &bp_pa, &bp_size); + bman_set_memory(sc, bp_pa, bp_size); - error = BM_GetRevision(sc->sc_bh, &rev); - if (error != E_OK) - goto err; + /* Warn if FBPR drops below 5% total. */ + bus_write_4(sc->sc_rres, FBPR_FP_LWIT, (bp_size / 8) / 20); + + /* Clear interrupt status, and enable all interrupts. */ + bus_write_4(sc->sc_rres, BMAN_ERR_ISR, 0xffffffff); + bus_write_4(sc->sc_rres, BMAN_ERR_IER, 0xffffffff); + bus_write_4(sc->sc_rres, BMAN_ERR_ISDR, 0); - device_printf(dev, "Hardware version: %d.%d.\n", - rev.majorRev, rev.minorRev); + /* Enable the IRQ line now. */ + if (bus_setup_intr(dev, sc->sc_ires, INTR_TYPE_NET, NULL, bman_isr, + sc, &sc->sc_icookie) != 0) + goto err; return (0); @@ -147,9 +223,10 @@ bman_detach(device_t dev) sc = device_get_softc(dev); - if (sc->sc_bh != NULL) - BM_Free(sc->sc_bh); - + if (sc->sc_vmem != NULL) + vmem_destroy(sc->sc_vmem); + if (sc->sc_icookie != NULL) + bus_teardown_intr(dev, sc->sc_ires, sc->sc_icookie); if (sc->sc_ires != NULL) bus_release_resource(dev, SYS_RES_IRQ, sc->sc_irid, sc->sc_ires); @@ -186,179 +263,105 @@ bman_shutdown(device_t dev) * BMAN API */ -t_Handle -bman_pool_create(uint8_t *bpid, uint16_t bufferSize, uint16_t maxBuffers, - uint16_t minBuffers, uint16_t allocBuffers, t_GetBufFunction *f_GetBuf, - t_PutBufFunction *f_PutBuf, uint32_t dep_sw_entry, uint32_t dep_sw_exit, - uint32_t dep_hw_entry, uint32_t dep_hw_exit, - t_BmDepletionCallback *f_Depletion, t_Handle h_BufferPool, - t_PhysToVirt *f_PhysToVirt, t_VirtToPhys *f_VirtToPhys) +struct bman_pool * +bman_new_pool(void) { - uint32_t thresholds[MAX_DEPLETION_THRESHOLDS]; struct bman_softc *sc; - t_Handle pool, portal; - t_BmPoolParam bpp; - int error; + vmem_addr_t bpid; + struct bman_pool *pool; sc = bman_sc; pool = NULL; - sched_pin(); - - portal = bman_portal_setup(sc); - if (portal == NULL) - goto err; - - memset(&bpp, 0, sizeof(bpp)); - bpp.h_Bm = sc->sc_bh; - bpp.h_BmPortal = portal; - bpp.h_App = h_BufferPool; - bpp.numOfBuffers = allocBuffers; - - bpp.bufferPoolInfo.h_BufferPool = h_BufferPool; - bpp.bufferPoolInfo.f_GetBuf = f_GetBuf; - bpp.bufferPoolInfo.f_PutBuf = f_PutBuf; - bpp.bufferPoolInfo.f_PhysToVirt = f_PhysToVirt; - bpp.bufferPoolInfo.f_VirtToPhys = f_VirtToPhys; - bpp.bufferPoolInfo.bufferSize = bufferSize; - - pool = BM_POOL_Config(&bpp); - if (pool == NULL) - goto err; - - /* - * Buffer context must be disabled on FreeBSD - * as it could cause memory corruption. - */ - BM_POOL_ConfigBuffContextMode(pool, 0); - - if (minBuffers != 0 || maxBuffers != 0) { - error = BM_POOL_ConfigStockpile(pool, maxBuffers, minBuffers); - if (error != E_OK) - goto err; - } - - if (f_Depletion != NULL) { - thresholds[BM_POOL_DEP_THRESH_SW_ENTRY] = dep_sw_entry; - thresholds[BM_POOL_DEP_THRESH_SW_EXIT] = dep_sw_exit; - thresholds[BM_POOL_DEP_THRESH_HW_ENTRY] = dep_hw_entry; - thresholds[BM_POOL_DEP_THRESH_HW_EXIT] = dep_hw_exit; - error = BM_POOL_ConfigDepletion(pool, f_Depletion, thresholds); - if (error != E_OK) - goto err; - } - - error = BM_POOL_Init(pool); - if (error != E_OK) - goto err; + if (vmem_alloc(sc->sc_vmem, 1, M_FIRSTFIT | M_NOWAIT, &bpid) != 0) + return (NULL); - *bpid = BM_POOL_GetId(pool); - sc->sc_bpool_cpu[*bpid] = PCPU_GET(cpuid); + pool = malloc(sizeof(*pool), M_BMAN, M_WAITOK | M_ZERO); - sched_unpin(); + pool->bpid = bpid; return (pool); - -err: - if (pool != NULL) - BM_POOL_Free(pool); - - sched_unpin(); - - return (NULL); } -int -bman_pool_destroy(t_Handle pool) +struct bman_pool * +bman_pool_create(uint8_t *bpid, uint16_t buffer_size, uint16_t max_buffers, + uint32_t dep_sw_entry, uint32_t dep_sw_exit, + uint32_t dep_hw_entry, uint32_t dep_hw_exit, + bm_depletion_handler dep_cb, void *arg) { struct bman_softc *sc; + struct bman_pool *bp; sc = bman_sc; - thread_lock(curthread); - sched_bind(curthread, sc->sc_bpool_cpu[BM_POOL_GetId(pool)]); - thread_unlock(curthread); + bp = bman_new_pool(); + if (bpid != NULL) + *bpid = bp->bpid; + + if (dep_cb) { + bp->dep_cb = dep_cb; + bus_write_4(sc->sc_rres, BMAN_POOL_SWDET(bp->bpid), + dep_sw_entry); + bus_write_4(sc->sc_rres, BMAN_POOL_SWDXT(bp->bpid), + dep_sw_exit); + bus_write_4(sc->sc_rres, BMAN_POOL_HWDET(bp->bpid), + dep_hw_entry); + bus_write_4(sc->sc_rres, BMAN_POOL_HWDXT(bp->bpid), + dep_hw_exit); + bp->arg = arg; + bman_portal_enable_scn(DPCPU_GET(bman_affine_portal), bp); + } - BM_POOL_Free(pool); + return (bp); +} - thread_lock(curthread); - sched_unbind(curthread); - thread_unlock(curthread); +int +bman_pool_destroy(struct bman_pool *pool) +{ + /* Need to error, or print a warning, if the pool isn't empty */ + if (bman_count(pool) != 0) + return (EBUSY); + vmem_free(bman_sc->sc_vmem, pool->bpid, 1); + free(pool, M_BMAN); return (0); } int -bman_pool_fill(t_Handle pool, uint16_t nbufs) +bman_put_buffers(struct bman_pool *pool, struct bman_buffer *buffers, int count) { - struct bman_softc *sc; - t_Handle portal; + struct bman_portal_softc *portal; int error; - sc = bman_sc; - sched_pin(); + critical_enter(); - portal = bman_portal_setup(sc); + portal = DPCPU_GET(bman_affine_portal); if (portal == NULL) { - sched_unpin(); + critical_exit(); return (EIO); } - error = BM_POOL_FillBufs(pool, portal, nbufs); - - sched_unpin(); - - return ((error == E_OK) ? 0 : EIO); -} - -void * -bman_get_buffer(t_Handle pool) -{ - struct bman_softc *sc; - t_Handle portal; - void *buffer; - - sc = bman_sc; - sched_pin(); - - portal = bman_portal_setup(sc); - if (portal == NULL) { - sched_unpin(); - return (NULL); + while (count > 0) { + int c = min(count, 8); + error = bman_release(pool, buffers, c); + buffers += c; + count -= c; } - buffer = BM_POOL_GetBuf(pool, portal); + critical_exit(); - sched_unpin(); - - return (buffer); + return (error); } -int -bman_put_buffer(t_Handle pool, void *buffer) +uint32_t +bman_get_bpid(struct bman_pool *pool) { - struct bman_softc *sc; - t_Handle portal; - int error; - - sc = bman_sc; - sched_pin(); - - portal = bman_portal_setup(sc); - if (portal == NULL) { - sched_unpin(); - return (EIO); - } - - error = BM_POOL_PutBuf(pool, portal, buffer); - - sched_unpin(); - - return ((error == E_OK) ? 0 : EIO); + return (pool->bpid); } uint32_t -bman_count(t_Handle pool) +bman_count(struct bman_pool *pool) { - return (BM_POOL_GetCounter(pool, e_BM_POOL_COUNTERS_CONTENT)); + return (bus_read_4(bman_sc->sc_rres, BMAN_POOL_CONTENT(pool->bpid))); } + diff --git a/sys/dev/dpaa/bman.h b/sys/dev/dpaa/bman.h index 01c09489890c..118c6f5938bc 100644 --- a/sys/dev/dpaa/bman.h +++ b/sys/dev/dpaa/bman.h @@ -1,3 +1,9 @@ +/* + * Copyright (c) 2026 Justin Hibbits + * + * SPDX-License-Identifier: BSD-2-Clause + */ + /*- * Copyright (c) 2011-2012 Semihalf. * All rights reserved. @@ -27,29 +33,16 @@ #ifndef _BMAN_H #define _BMAN_H +#include <sys/vmem.h> #include <machine/vmparam.h> -#include <contrib/ncsw/inc/Peripherals/bm_ext.h> - /* * BMAN Configuration */ -/* Maximum number of buffers in all BMAN pools */ -#define BMAN_MAX_BUFFERS 4096 - /* * Portal definitions */ -#define BMAN_CE_PA(base) (base) -#define BMAN_CI_PA(base) ((base) + 0x100000) - -#define BMAN_PORTAL_CE_PA(base, n) \ - (BMAN_CE_PA(base) + ((n) * BMAN_PORTAL_CE_SIZE)) -#define BMAN_PORTAL_CI_PA(base, n) \ - (BMAN_CI_PA(base) + ((n) * BMAN_PORTAL_CI_SIZE)) - -#define BMAN_CCSR_SIZE 0x1000 struct bman_softc { device_t sc_dev; /* device handle */ @@ -57,129 +50,42 @@ struct bman_softc { struct resource *sc_rres; /* register resource */ int sc_irid; /* interrupt rid */ struct resource *sc_ires; /* interrupt resource */ + void *sc_icookie; + vmem_t *sc_vmem; /* resource pool */ + int sc_major; + int sc_minor; +}; - bool sc_regs_mapped[MAXCPU]; /* register mapping status */ +struct bman_buffer { + uint16_t bpid; + uint16_t buf_hi; + uint32_t buf_lo; +} __aligned(8); - t_Handle sc_bh; /* BMAN handle */ - t_Handle sc_bph[MAXCPU]; /* BMAN portal handles */ - vm_paddr_t sc_bp_pa; /* BMAN portals PA */ - unsigned int sc_bpool_cpu[BM_MAX_NUM_OF_POOLS]; -}; +struct bman_pool; +struct bman_buffer; -/* - * External API - */ +typedef void (*bm_depletion_handler)(void *, bool); /* - * @brief Function to create BMAN pool. - * - * @param bpid The pointer to variable where Buffer Pool ID will be - * stored. - * - * @param bufferSize The size of buffers in newly created pool. - * - * @param maxBuffers The maximum number of buffers in software stockpile. - * Set to 0 if software stockpile should not be created. - * - * @param minBuffers The minimum number of buffers in software stockpile. - * Set to 0 if software stockpile should not be created. - * - * @param allocBuffers The number of buffers to preallocate during pool - * creation. - * - * @param f_GetBuf The buffer allocating function. Called only by - * bman_pool_create() and bman_pool_fill(). - * - * @param f_PutBuf The buffer freeing function. Called only by - * bman_pool_destroy(). - * - * @param dep_sw_entry The software portal depletion entry threshold. - * Set to 0 if depletion should not be signaled on - * software portal. - * - * @param dep_sw_exit The software portal depletion exit threshold. - * Set to 0 if depletion should not be signaled on - * software portal. - * - * @param dep_hw_entry The hardware portal depletion entry threshold. - * Set to 0 if depletion should not be signaled on - * hardware portal. - * - * @param dep_hw_exit The hardware portal depletion exit threshold. - * Set to 0 if depletion should not be signaled on - * hardware portal. - * - * @param f_Depletion The software portal depletion notification function. - * Set to NULL if depletion notification is not used. - * - * @param h_BufferPool The user provided buffer pool context passed to - * f_GetBuf, f_PutBuf and f_Depletion functions. - * - * @param f_PhysToVirt The PA to VA translation function. Set to NULL if - * default one should be used. - * - * @param f_VirtToPhys The VA to PA translation function. Set to NULL if - * default one should be used. - * - * @returns Handle to newly created BMAN pool or NULL on error. - * - * @cautions If pool uses software stockpile, all accesses to given - * pool must be protected by lock. Even if only hardware - * portal depletion notification is used, the caller must - * provide valid @p f_Depletion function. + * External API */ -t_Handle bman_pool_create(uint8_t *bpid, uint16_t bufferSize, - uint16_t maxBuffers, uint16_t minBuffers, uint16_t allocBuffers, - t_GetBufFunction *f_GetBuf, t_PutBufFunction *f_PutBuf, - uint32_t dep_sw_entry, uint32_t dep_sw_exit, uint32_t dep_hw_entry, - uint32_t dep_hw_exit, t_BmDepletionCallback *f_Depletion, - t_Handle h_BufferPool, t_PhysToVirt *f_PhysToVirt, - t_VirtToPhys *f_VirtToPhys); -/* - * @brief Fill pool with buffers. - * - * The bman_pool_fill() function fills the BMAN pool with buffers. The buffers - * are allocated through f_GetBuf function (see bman_pool_create() description). - * - * @param pool The BMAN pool handle. - * @param nbufs The number of buffers to allocate. To maximize - * performance this value should be multiple of 8. - * - * @returns Zero on success or error code on failure. - */ -int bman_pool_fill(t_Handle pool, uint16_t nbufs); +struct bman_pool *bman_new_pool(void); +struct bman_pool *bman_pool_create(uint8_t *bpid, uint16_t buffer_size, + uint16_t max_buffers, uint32_t dep_sw_entry, uint32_t dep_sw_exit, uint32_t + dep_hw_entry, uint32_t dep_hw_exit, bm_depletion_handler dep_cb, void *arg); /* * @brief Destroy pool. * - * The bman_pool_destroy() function destroys the BMAN pool. Buffers for pool - * are free through f_PutBuf function (see bman_pool_create() description). - * - * @param pool The BMAN pool handle. - * - * @returns Zero on success or error code on failure. - */ -int bman_pool_destroy(t_Handle pool); - -/* - * @brief Get a buffer from BMAN pool. + * The bman_pool_destroy() function destroys the BMAN pool. + * The buffer pool must be empty. * * @param pool The BMAN pool handle. - * - * @returns Pointer to the buffer or NULL if pool is empty. + * @return 0 on success, EBUSY if the pool is not empty. */ -void *bman_get_buffer(t_Handle pool); - -/* - * @brief Put a buffer to BMAN pool. - * - * @param pool The BMAN pool handle. - * @param buffer The pointer to buffer. - * - * @returns Zero on success or error code on failure. - */ -int bman_put_buffer(t_Handle pool, void *buffer); +int bman_pool_destroy(struct bman_pool *pool); /* * @brief Count free buffers in given pool. @@ -188,7 +94,25 @@ int bman_put_buffer(t_Handle pool, void *buffer); * * @returns Number of free buffers in pool. */ -uint32_t bman_count(t_Handle pool); +uint32_t bman_count(struct bman_pool *pool); + +int bman_put_buffers(struct bman_pool *, struct bman_buffer *, int); +static inline int +bman_put_buffer(struct bman_pool *p, vm_paddr_t buf, int bpid) +{ + struct bman_buffer b = { + .bpid = bpid, + .buf_hi = ((uintptr_t)buf) >> 32, + .buf_lo = ((uintptr_t)buf) & 0xffffffff + }; + return (bman_put_buffers(p, &b, 1)); +} + +int bman_acquire(struct bman_pool *, struct bman_buffer *, uint8_t); + +int bman_create_affine_portal(device_t, vm_offset_t, vm_offset_t, int); +void bman_destroy_affine_portal(int); +uint32_t bman_get_bpid(struct bman_pool *); /* * Bus i/f diff --git a/sys/dev/dpaa/bman_fdt.c b/sys/dev/dpaa/bman_fdt.c index 330db7b89715..c77d58cf118d 100644 --- a/sys/dev/dpaa/bman_fdt.c +++ b/sys/dev/dpaa/bman_fdt.c @@ -40,6 +40,7 @@ #include <dev/ofw/ofw_subr.h> #include "bman.h" +#include "bman_var.h" #include "portals.h" #define FBMAN_DEVSTR "Freescale Buffer Manager" @@ -59,12 +60,7 @@ static device_method_t bman_methods[] = { DEVMETHOD_END }; -static driver_t bman_driver = { - "bman", - bman_methods, - sizeof(struct bman_softc), -}; - +DEFINE_CLASS_0(bman, bman_driver, bman_methods, sizeof(struct bman_softc)); EARLY_DRIVER_MODULE(bman, simplebus, bman_driver, 0, 0, BUS_PASS_SUPPORTDEV); static int @@ -82,144 +78,46 @@ bman_fdt_probe(device_t dev) /* * BMAN Portals */ -#define BMAN_PORT_DEVSTR "Freescale Buffer Manager - Portals" +#define BMAN_PORT_DEVSTR "Freescale Buffer Manager - Portal" -static device_probe_t bman_portals_fdt_probe; -static device_attach_t bman_portals_fdt_attach; +static int portal_ncpus; +static device_probe_t bman_portal_fdt_probe; +static device_attach_t bman_portal_fdt_attach; -static device_method_t bm_portals_methods[] = { +static device_method_t bman_portal_methods[] = { /* Device interface */ - DEVMETHOD(device_probe, bman_portals_fdt_probe), - DEVMETHOD(device_attach, bman_portals_fdt_attach), - DEVMETHOD(device_detach, bman_portals_detach), + DEVMETHOD(device_probe, bman_portal_fdt_probe), + DEVMETHOD(device_attach, bman_portal_fdt_attach), + DEVMETHOD(device_detach, bman_portal_detach), DEVMETHOD_END }; -static driver_t bm_portals_driver = { - "bman-portals", - bm_portals_methods, - sizeof(struct dpaa_portals_softc), -}; - -EARLY_DRIVER_MODULE(bman_portals, ofwbus, bm_portals_driver, 0, 0, - BUS_PASS_BUS); - -static void -get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep) -{ - - *addrp = 2; - *sizep = 1; - OF_getencprop(node, "#address-cells", addrp, sizeof(*addrp)); - OF_getencprop(node, "#size-cells", sizep, sizeof(*sizep)); -} +DEFINE_CLASS_0(bman_portal, bman_portal_driver, bman_portal_methods, + sizeof(struct bman_portal_softc)); +EARLY_DRIVER_MODULE(bman_portal, simplebus, bman_portal_driver, 0, 0, + BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE); static int -bman_portals_fdt_probe(device_t dev) +bman_portal_fdt_probe(device_t dev) { - phandle_t node; - - if (ofw_bus_is_compatible(dev, "simple-bus")) { - node = ofw_bus_get_node(dev); - for (node = OF_child(node); node > 0; node = OF_peer(node)) { - if (ofw_bus_node_is_compatible(node, "fsl,bman-portal")) - break; - } - if (node <= 0) - return (ENXIO); - } else if (!ofw_bus_is_compatible(dev, "fsl,bman-portals")) + if (!ofw_bus_is_compatible(dev, "fsl,bman-portal")) return (ENXIO); device_set_desc(dev, BMAN_PORT_DEVSTR); - return (BUS_PROBE_DEFAULT); } static int -bman_portals_fdt_attach(device_t dev) +bman_portal_fdt_attach(device_t dev) { - struct dpaa_portals_softc *sc; - struct resource_list_entry *rle; - phandle_t node, child, cpu_node; - vm_paddr_t portal_pa; - vm_size_t portal_size; - uint32_t addr, size; - ihandle_t cpu; - int cpu_num, cpus, intr_rid; - struct dpaa_portals_devinfo di; - struct ofw_bus_devinfo ofw_di = {}; + int portal_cpu = portal_ncpus; - cpus = 0; - sc = device_get_softc(dev); - sc->sc_dev = dev; - - node = ofw_bus_get_node(dev); - get_addr_props(node, &addr, &size); - - /* Find portals tied to CPUs */ - for (child = OF_child(node); child != 0; child = OF_peer(child)) { - if (cpus >= mp_ncpus) - break; - if (!ofw_bus_node_is_compatible(child, "fsl,bman-portal")) { - continue; - } - /* Checkout related cpu */ - if (OF_getprop(child, "cpu-handle", (void *)&cpu, - sizeof(cpu)) > 0) { - cpu_node = OF_instance_to_package(cpu); - /* Acquire cpu number */ - if (OF_getencprop(cpu_node, "reg", &cpu_num, sizeof(cpu_num)) <= 0) { - device_printf(dev, "Could not retrieve CPU number.\n"); - return (ENXIO); - } - } else - cpu_num = cpus; - - cpus++; - - if (ofw_bus_gen_setup_devinfo(&ofw_di, child) != 0) { - device_printf(dev, "could not set up devinfo\n"); - continue; - } - - resource_list_init(&di.di_res); - if (ofw_bus_reg_to_rl(dev, child, addr, size, &di.di_res)) { - device_printf(dev, "%s: could not process 'reg' " - "property\n", ofw_di.obd_name); - ofw_bus_gen_destroy_devinfo(&ofw_di); - continue; - } - if (ofw_bus_intr_to_rl(dev, child, &di.di_res, &intr_rid)) { - device_printf(dev, "%s: could not process " - "'interrupts' property\n", ofw_di.obd_name); - resource_list_free(&di.di_res); - ofw_bus_gen_destroy_devinfo(&ofw_di); - continue; - } - di.di_intr_rid = intr_rid; - - ofw_reg_to_paddr(child, 0, &portal_pa, &portal_size, NULL); - rle = resource_list_find(&di.di_res, SYS_RES_MEMORY, 0); - - if (sc->sc_dp_pa == 0) - sc->sc_dp_pa = portal_pa - rle->start; - - portal_size = rle->end + 1; - rle = resource_list_find(&di.di_res, SYS_RES_MEMORY, 1); - portal_size = ulmax(rle->end + 1, portal_size); - sc->sc_dp_size = ulmax(sc->sc_dp_size, portal_size); - - if (dpaa_portal_alloc_res(dev, &di, cpu_num)) - goto err; - } + /* Don't attach to more portals than we have CPUs */ + if (mp_ncpus == portal_ncpus) + return (ENXIO); - ofw_bus_gen_destroy_devinfo(&ofw_di); + portal_ncpus++; - return (bman_portals_attach(dev)); -err: - resource_list_free(&di.di_res); - ofw_bus_gen_destroy_devinfo(&ofw_di); - bman_portals_detach(dev); - return (ENXIO); + return (bman_portal_attach(dev, portal_cpu)); } diff --git a/sys/dev/dpaa/bman_portals.c b/sys/dev/dpaa/bman_portals.c index 10c788410e1c..b0c8200c1880 100644 --- a/sys/dev/dpaa/bman_portals.c +++ b/sys/dev/dpaa/bman_portals.c @@ -1,27 +1,7 @@ -/*- - * Copyright (c) 2012 Semihalf. - * All rights reserved. +/* + * Copyright (c) 2026 Justin Hibbits * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * SPDX-License-Identifier: BSD-2-Clause */ #include "opt_platform.h" @@ -30,6 +10,8 @@ #include <sys/systm.h> #include <sys/kernel.h> #include <sys/bus.h> +#include <sys/cpuset.h> +#include <sys/interrupt.h> #include <sys/lock.h> #include <sys/module.h> #include <sys/mutex.h> @@ -46,132 +28,300 @@ #include <powerpc/mpc85xx/mpc85xx.h> #include "bman.h" +#include "bman_var.h" #include "portals.h" -t_Handle bman_portal_setup(struct bman_softc *); +#define BCSP_CFG 0x0100 +#define CFG_RPM_M 0x00000003 +#define CFG_RPM_PI 0x00000000 +#define CFG_RPM_PE 0x00000001 +#define CFG_RPM_VBM 0x00000002 +#define BCSP_SCN0 0x0200 +#define BCSP_SCN1 0x0204 +#define BCSP_ISR 0x0e00 +#define BCSP_IER 0x0e04 +#define BCSP_ISDR 0x0e08 +#define INTR_RCDI 0x00000004 +#define INTR_RCRI 0x00000002 +#define INTR_BSCN 0x00000001 + +#define BMAN_CE_CR 0x0000 +#define BMAN_CE_RR0 0x0100 +#define BMAN_CE_RR1 0x0140 +#define BMAN_CE_RR(n) (BMAN_CE_RR0 + 0x40 * (n)) +#define BMAN_CE_RCR 0x1000 +#define BCSP_RCR_PI_CENA 0x3000 +#define BCSP_RCR_CI_CENA 0x3100 +#define BCSP_RCR_PI_CINH 0x000 +#define BCSP_RCR_CI_CINH 0x004 + +#define BMAN_MC_VERB_VBIT 0x80 +#define BMAN_MC_VERB_ACQUIRE 0x10 +#define BMAN_MC_VERB_QUERY 0x40 +#define BMAN_RCR_VERB_BPID0 0x20 +#define BMAN_RCR_VERB_BPID_BUF 0x30 + +struct bman_mc_command { + uint8_t verb; + uint8_t cd; + uint8_t rsvd[62]; +}; + +union bman_mc_result { + struct { + uint8_t verb; + uint8_t cd; + uint8_t rsvd[62]; + }; + struct { + uint64_t rsvd_q1[5]; + uint64_t bp_as; + uint64_t rsvd_q2; + uint64_t bp_ds; + }; + struct bman_buffer bufs[8]; +}; + +struct bman_rcr_entry { + union { + struct { + uint8_t verb; + uint8_t bpid; + uint8_t rsvd[62]; + }; + struct bman_buffer bufs[8]; + }; +}; + +static void bman_portal_isr(void *arg); + +static union bman_mc_result *bman_mc_send(struct bman_portal_softc *p, + uint8_t verb, uint8_t cd); -struct dpaa_portals_softc *bp_sc; +DPCPU_DEFINE(struct bman_portal_softc *, bman_affine_portal); + +DPAA_RING(bman_rcr, 8, BCSP_RCR_PI_CENA, BCSP_RCR_CI_CENA, + BCSP_RCR_PI_CINH, BCSP_RCR_CI_CINH); + +static uint32_t +bm_ci_read(struct bman_portal_softc *sc, bus_size_t off) +{ + return (bus_read_4(sc->sc_base.sc_mres[1], off)); +} + +static void +bm_ci_write(struct bman_portal_softc *sc, bus_size_t off, uint32_t val) +{ + bus_write_4(sc->sc_base.sc_mres[1], off, val); +} int -bman_portals_attach(device_t dev) +bman_portal_attach(device_t dev, int cpu) { - struct dpaa_portals_softc *sc; + struct bman_portal_softc *sc = device_get_softc(dev); - sc = bp_sc = device_get_softc(dev); - - /* Map bman portal to physical address space */ - if (law_enable(OCP85XX_TGTIF_BMAN, sc->sc_dp_pa, sc->sc_dp_size)) { - bman_portals_detach(dev); - return (ENXIO); - } - /* Set portal properties for XX_VirtToPhys() */ - XX_PortalSetInfo(dev); + sc->sc_base.sc_cpu = cpu; + dpaa_portal_alloc_res(dev, cpu); + + bm_ci_write(sc, BCSP_ISDR, 0); + bm_ci_write(sc, BCSP_IER, INTR_RCRI | INTR_BSCN); + bus_setup_intr(dev, sc->sc_base.sc_ires, INTR_TYPE_NET | INTR_MPSAFE, + NULL, bman_portal_isr, sc, &sc->sc_base.sc_intr_cookie); + bus_bind_intr(dev, sc->sc_base.sc_ires, cpu); + + /* Select valid-bit mode for rings */ + bus_write_4(sc->sc_base.sc_mres[1], BCSP_CFG, CFG_RPM_VBM); + /* Disable pool depletion notifications. */ + bm_ci_write(sc, BCSP_SCN0, 0); + bm_ci_write(sc, BCSP_SCN1, 0); + + DPCPU_ID_SET(cpu, bman_affine_portal, sc); + + sc->sc_rcr.ring = + (struct bman_rcr_entry *)(sc->sc_base.sc_ce_va + BMAN_CE_RCR); + bman_rcr_ring_init(&sc->sc_rcr, &sc->sc_base); + /* Starting MC polarity is always 1 */ + sc->mc.polarity = BMAN_MC_VERB_VBIT; - bus_attach_children(dev); return (0); } int -bman_portals_detach(device_t dev) +bman_portal_detach(device_t dev) { - struct dpaa_portals_softc *sc; + struct bman_portal_softc *sc; int i; - bp_sc = NULL; sc = device_get_softc(dev); - for (i = 0; i < ARRAY_SIZE(sc->sc_dp); i++) { - if (sc->sc_dp[i].dp_ph != NULL) { - thread_lock(curthread); - sched_bind(curthread, i); - thread_unlock(curthread); - BM_PORTAL_Free(sc->sc_dp[i].dp_ph); + /* TODO: Unmap TLB regions */ + thread_lock(curthread); + sched_bind(curthread, sc->sc_base.sc_cpu); + thread_unlock(curthread); - thread_lock(curthread); - sched_unbind(curthread); - thread_unlock(curthread); - } + if (sc->sc_base.sc_ires != NULL) + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_base.sc_ires); - if (sc->sc_dp[i].dp_ires != NULL) { - XX_DeallocIntr((uintptr_t)sc->sc_dp[i].dp_ires); - bus_release_resource(dev, SYS_RES_IRQ, - sc->sc_dp[i].dp_irid, sc->sc_dp[i].dp_ires); - } - } - for (i = 0; i < ARRAY_SIZE(sc->sc_rres); i++) { - if (sc->sc_rres[i] != NULL) + for (i = 0; i < nitems(sc->sc_base.sc_mres); i++) { + if (sc->sc_base.sc_mres[i] != NULL) bus_release_resource(dev, SYS_RES_MEMORY, - sc->sc_rrid[i], - sc->sc_rres[i]); + i, sc->sc_base.sc_mres[i]); } + thread_lock(curthread); + sched_unbind(curthread); + thread_unlock(curthread); + return (0); } -t_Handle -bman_portal_setup(struct bman_softc *bsc) +static uint64_t +bman_query(struct bman_portal_softc *sc, bool depletion) { - struct dpaa_portals_softc *sc; - t_BmPortalParam bpp; - t_Handle portal; - unsigned int cpu; - uintptr_t p; + union bman_mc_result *mc_res; + uint64_t res; - /* Return NULL if we're not ready or while detach */ - if (bp_sc == NULL) - return (NULL); + critical_enter(); + mc_res = bman_mc_send(sc, BMAN_MC_VERB_QUERY, 0); + if (mc_res == NULL) + goto err; - sc = bp_sc; + if (depletion) + res = mc_res->bp_ds; + else + res = mc_res->bp_as; + critical_exit(); - sched_pin(); - portal = NULL; - cpu = PCPU_GET(cpuid); + return (res); - /* Check if portal is ready */ - while (atomic_cmpset_acq_ptr((uintptr_t *)&sc->sc_dp[cpu].dp_ph, - 0, -1) == 0) { - p = atomic_load_acq_ptr((uintptr_t *)&sc->sc_dp[cpu].dp_ph); +err: + critical_exit(); + device_printf(sc->sc_base.sc_dev, "Timeout querying depltetion\n"); + return (0); +} - /* Return if portal is already initialized */ - if (p != 0 && p != -1) { - sched_unpin(); - return ((t_Handle)p); - } +static void +bman_portal_isr(void *arg) +{ + struct bman_portal_softc *sc = arg; + uint32_t intrs; + + intrs = bm_ci_read(sc, BCSP_ISR); - /* Not inititialized and "owned" by another thread */ - sched_relinquish(curthread); + /* Release Command Ring interrupt. */ + if (intrs & INTR_RCRI) { + bman_rcr_update(&sc->sc_rcr, &sc->sc_base); + } + /* Buffer Pool State Change Notification. */ + if (intrs & INTR_BSCN) { + struct bman_pool *pool; + uint64_t res = bman_query(sc, true); + if (__predict_true(res != 0)) { + int idx = flsll(res); + pool = sc->sc_pools[64 - idx]; + KASSERT(pool != NULL, + ("state change on unassociated bpid %d\n", idx)); + pool->dep_cb(pool->arg, true); + } } - /* Map portal registers */ - dpaa_portal_map_registers(sc); + bm_ci_write(sc, BCSP_ISR, intrs); +} - /* Configure and initialize portal */ - bpp.ceBaseAddress = rman_get_bushandle(sc->sc_rres[0]); - bpp.ciBaseAddress = rman_get_bushandle(sc->sc_rres[1]); - bpp.h_Bm = bsc->sc_bh; - bpp.swPortalId = cpu; - bpp.irq = (uintptr_t)sc->sc_dp[cpu].dp_ires; +/* RCR */ - portal = BM_PORTAL_Config(&bpp); - if (portal == NULL) - goto err; +int +bman_release(struct bman_pool *pool, const struct bman_buffer *bufs, + uint8_t count) +{ + struct bman_portal_softc *portal; + struct bman_rcr_entry *rcr; - if (BM_PORTAL_Init(portal) != E_OK) - goto err; + if (count > 8) + return (EINVAL); - atomic_store_rel_ptr((uintptr_t *)&sc->sc_dp[cpu].dp_ph, (uintptr_t)portal); - - sched_unpin(); + critical_enter(); + portal = DPCPU_GET(bman_affine_portal); + rcr = bman_rcr_start(&portal->sc_rcr, &portal->sc_base); + bzero(rcr, sizeof(*rcr)); - return (portal); + /* This should be safe, because bpid must be less than 256. */ + for (int i = 0; i < count; i++) + rcr->bufs[i] = bufs[i]; + rcr->bufs[0].bpid = pool->bpid; + bman_rcr_commit(&portal->sc_rcr, BMAN_RCR_VERB_BPID0 | count); + critical_exit(); -err: - if (portal != NULL) - BM_PORTAL_Free(portal); + return (0); +} + +/* MC commands */ +/* Assumes pinned */ +static union bman_mc_result * +bman_mc_send(struct bman_portal_softc *p, uint8_t verb, uint8_t cd) +{ + int res_idx; + struct bman_mc_command *command; + union bman_mc_result *rr; + uintptr_t ce_va = p->sc_base.sc_ce_va; + + command = (struct bman_mc_command *)(ce_va + BMAN_CE_CR); + dpaa_zero_line(command); + command->cd = cd; + dpaa_lw_barrier(); + command->verb = verb | p->mc.polarity; + res_idx = (p->mc.polarity ? 1 : 0); + p->mc.polarity ^= BMAN_MC_VERB_VBIT; + dpaa_flush_line(command); - atomic_store_rel_ptr((uintptr_t *)&sc->sc_dp[cpu].dp_ph, 0); - sched_unpin(); + rr = (union bman_mc_result *)(ce_va + BMAN_CE_RR(res_idx)); + for (;;) { + if (rr->verb != 0) + break; + dpaa_flush_line(rr); + } + return (rr); +} + +int +bman_acquire(struct bman_pool *pool, struct bman_buffer *bufs, uint8_t count) +{ + union bman_mc_result *rr; + + if (count > 8 || count == 0) + return (EINVAL); + critical_enter(); + rr = bman_mc_send(DPCPU_GET(bman_affine_portal), + BMAN_MC_VERB_ACQUIRE | count, + pool->bpid); + critical_exit(); + + if (rr == NULL) + return (ETIMEDOUT); + if ((rr->verb & ~BMAN_MC_VERB_VBIT) == 0) + return (ENOMEM); + + memcpy(bufs, rr, count * sizeof(*bufs)); + + return (0); +} + +/* + * Enable pool state change notifications on this portal. This requires the + * pool to already be configured with the callback to handle state changes. + */ +void +bman_portal_enable_scn(struct bman_portal_softc *sc, struct bman_pool *pool) +{ + uint32_t reg, reg_ptr; - return (NULL); + if (pool->bpid >= 32) + reg_ptr = BCSP_SCN1; + else + reg_ptr = BCSP_SCN0; + reg = bm_ci_read(sc, reg_ptr); + reg |= (1 << (31 - pool->bpid)); + bm_ci_write(sc, reg_ptr, reg); + sc->sc_pools[pool->bpid] = pool; } diff --git a/sys/dev/dpaa/bman_var.h b/sys/dev/dpaa/bman_var.h new file mode 100644 index 000000000000..91484da61ac3 --- /dev/null +++ b/sys/dev/dpaa/bman_var.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2026 Justin Hibbits + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef BMAN_VAR_H +#define BMAN_VAR_H + +#include "dpaa_common.h" +#include "portals.h" + +#define BMAN_MAX_POOLS 64 +#define BMAN_MAX_POOLS_1023 8 + +DPAA_RING_DECLARE(bman_rcr); + +struct bman_mc { + uint8_t polarity; + bool busy; +}; + +struct bman_portal_softc { + struct dpaa_portal_softc sc_base; + + struct bman_mc mc; + struct bman_rcr_ring sc_rcr; + struct bman_pool *sc_pools[BMAN_MAX_POOLS]; +}; + +struct bman_pool { + uint32_t bpid; + bm_depletion_handler dep_cb; + void *arg; +}; + +DPCPU_DECLARE(struct bman_portal_softc *, bman_affine_portal); + +int bman_release(struct bman_pool *pool, const struct bman_buffer *bufs, + uint8_t count); + +void bman_portal_enable_scn(struct bman_portal_softc *, struct bman_pool *); + +#endif diff --git a/sys/dev/dpaa/dpaa_common.c b/sys/dev/dpaa/dpaa_common.c new file mode 100644 index 000000000000..c5055231298b --- /dev/null +++ b/sys/dev/dpaa/dpaa_common.c @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2026 Justin Hibbits + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <vm/vm.h> +#include <vm/pmap.h> + +#include <dev/fdt/fdt_common.h> +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> + +#include "dpaa_common.h" + +#define FDT_REG_CELLS 4 +int +dpaa_map_private_memory(device_t dev, int idx, const char *compat, + vm_paddr_t *addrp, size_t *sizep) +{ + phandle_t node; + pcell_t cells[idx + 1]; + pcell_t *cell_alloc; + int addr_cells, size_cells; + uint64_t tmp; + u_long align, base, size; + vm_paddr_t alloc_base; + vm_size_t alloc_range_size; + ssize_t alloc_size; + void *reserved; + int rv; + + node = ofw_bus_get_node(dev); + if (OF_getencprop(node, "memory-region", cells, sizeof(cells)) <= 0) + return (ENXIO); + + node = OF_node_from_xref(cells[idx]); + /* If the memory is already reserved, we just need to return it. */ + if (fdt_regsize(node, &base, &size) == 0) + goto success; + + rv = fdt_addrsize_cells(OF_parent(node), &addr_cells, &size_cells); + if (rv != 0) + return (rv); + + if (OF_getprop(node, "alignment", &tmp, sizeof(tmp)) <= 0) + return (ENXIO); + + align = fdt_data_get(&tmp, addr_cells); + if (OF_getprop(node, "size", &tmp, sizeof(tmp)) <= 0) + return (ENXIO); + size = fdt_data_get(&tmp, size_cells); + + alloc_size = + OF_getencprop_alloc(node, "alloc-ranges", (void **)&cell_alloc); + if (alloc_size < 0) + return (ENXIO); + + alloc_size /= sizeof(pcell_t); + for (int i = 0; i < alloc_size; i += (addr_cells + size_cells)) { + alloc_base = fdt_data_get(&cell_alloc[i], addr_cells); + alloc_range_size = + fdt_data_get(&cell_alloc[i + addr_cells], size_cells); + reserved = contigmalloc(size, M_DEVBUF, M_NOWAIT | M_ZERO, + alloc_base, alloc_base + alloc_range_size, align, 0); + if (reserved != NULL) + break; + } + if (reserved == NULL) + return (ENOMEM); + /* Flush the cache (zeroed memory) because it won't be touched later. */ + cpu_flush_dcache(reserved, size); + base = pmap_kextract((vm_offset_t)reserved); + +success: + *addrp = base; + *sizep = size; + + return (0); +} diff --git a/sys/dev/dpaa/dpaa_common.h b/sys/dev/dpaa/dpaa_common.h new file mode 100644 index 000000000000..8fa43a034ef5 --- /dev/null +++ b/sys/dev/dpaa/dpaa_common.h @@ -0,0 +1,195 @@ +/* + * Copyright (c) 2026 Justin Hibbits + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef DPAA_COMMON_H +#define DPAA_COMMON_H + +#include <machine/atomic.h> + +int dpaa_map_private_memory(device_t dev, int idx, const char *compat, + vm_paddr_t *addrp, size_t *sizep); + +struct dpaa_fd { + uint64_t liodn:8; + uint64_t bpid:8; + uint64_t eliodn:4; + uint64_t _rsvd1:4; + uint64_t addr:40; + uint32_t format:3; + uint32_t offset:9; + uint32_t length:20; + uint32_t cmd_stat; +} __packed; + +#define DPAA_FD_FORMAT_SHORT_MBSF 4 + +#define DPAA_FD_RX_STATUS_DCL4C 0x10000000 +#define DPAA_FD_RX_STATUS_DME 0x01000000 +#define DPAA_FD_RX_STATUS_IPRE_M 0x00300000 +#define DPAA_FD_RX_STATUS_FPE 0x00080000 +#define DPAA_FD_RX_STATUS_FSE 0x00040000 +#define DPAA_FD_RX_STATUS_DIS 0x00020000 +#define DPAA_FD_RX_STATUS_EOF 0x00008000 +#define DPAA_FD_RX_STATUS_NSS 0x00004000 +#define DPAA_FD_RX_STATUS_KSO 0x00002000 +#define DPAA_FD_RX_STATUS_FCL_M 0x00000c00 +#define DPAA_FD_RX_STATUS_IPP 0x00000200 +#define DPAA_FD_RX_STATUS_FLM 0x00000100 +#define DPAA_FD_RX_STATUS_PTE 0x00000080 +#define DPAA_FD_RX_STATUS_ISP 0x00000040 +#define DPAA_FD_RX_STATUS_PHE 0x00000020 +#define DPAA_FD_RX_STATUS_FRDR 0x00000010 +#define DPAA_FD_RX_STATUS_BLE 0x00000008 +#define DPAA_FD_RX_STATUS_L4CV 0x00000004 +#define DPAA_FD_RX_STATUS_IPR 0x00000001 + +#define DPAA_FD_TX_CMD_RPD 0x40000000 +#define DPAA_FD_TX_CMD_DTC 0x10000000 +#define DPAA_FD_TX_STATUS_UFD 0x04000000 +#define DPAA_FD_TX_STATUS_LGE 0x02000000 +#define DPAA_FD_TX_STATUS_DME 0x01000000 + +/* Most of the above are error flags, but some aren't */ +#define DPAA_FD_CMD_STAT_ERR_M 0x010ce3e8 +#define DPAA_FD_TX_STAT_ERR_M 0x03000000 + +#define DPAA_FD_GET_ADDR(fd) ((void *)PHYS_TO_DMAP(fd->addr)) + +struct dpaa_sgte { + uint64_t addr; + uint32_t extension:1; + uint32_t final:1; + uint32_t length:30; + uint16_t bpid; + uint16_t offset; +} __packed; +struct qman_fqr; + + +#define DPAA_NUM_OF_SG_TABLE_ENTRY 16 + +/* + * Ring API infrastructure + * + * BMan and QMan both use cache-enabled rings. Abstract this away to a more + * generalized interface to reduce code copying. + * + * Requirements: + * - Before calling <ring>_init() the ring base (ring->ring) must be initialized + * to the base of the ring. + */ +#define DPAA_RING_DECLARE(pfx) \ + struct pfx##_ring { \ + struct pfx##_entry *ring; \ + struct pfx##_entry *cursor; \ + uint8_t vbit; \ + uint8_t avail; \ + uint8_t ci; \ + uint8_t ithresh; \ + } + +/* + * Ring functions: + * + * ring_cyc_diff() -- get the (circular) difference of `l - f` + * ring_ring_init() -- Set up the ring structures. Portal must be + * initialized beforehand, and ring->ring must be nonzero. + * ring_CARRYCLEAR() -- stealth math to do circular roll-over + * ring_INC() -- Increment the cursor within the ring + * ring_update() -- Update ring entry availability count + * ring_start() -- Reserve the next entry in the ring if available. + * ring_commit() -- Commit the reserved ring entry by setting the verb and + * AVB bit + */ +#define DPAA_RING(pfx,sz,pi_e,ci_e,pi_i,ci_i) \ +static inline int \ +pfx##_cyc_diff(uint8_t size, uint8_t f, uint8_t l) \ +{ \ + if (f <= l) \ + return (uint8_t)(l - f); \ + return (uint8_t)(l + size - f); \ +} \ +static inline void \ +pfx##_ring_init(struct pfx##_ring *ring, struct dpaa_portal_softc *portal)\ +{ \ + uint32_t pi = *(uint32_t*)(portal->sc_ci_va + pi_i) & (sz - 1); \ + uint32_t ci = *(uint32_t*)(portal->sc_ci_va + ci_i); \ + ring->ci = ci & (sz - 1); \ + ring->vbit = !!(ci & sz) << 7; \ + ring->cursor = ring->ring + pi; \ + ring->avail = sz - 1 - pfx##_cyc_diff(sz, ring->ci, pi); \ +} \ +static inline void * \ +pfx##_CARRYCLEAR(struct pfx##_entry *p) \ +{ \ + return ((void *)((uintptr_t)p & (~(uintptr_t)(sz << 6)))); \ +} \ +static inline void \ +pfx##_INC(struct pfx##_ring *ring) \ +{ \ + struct pfx##_entry *partial = ring->cursor + 1; \ + ring->cursor = pfx##_CARRYCLEAR(partial); \ + if (partial != ring->cursor) \ + ring->vbit ^= 0x80; \ +} \ +static inline uint8_t \ +pfx##_update(struct pfx##_ring *ring, struct dpaa_portal_softc *portal) \ +{ \ + uint8_t diff, old_ci = ring->ci; \ + ring->ci = *(uint32_t*)(portal->sc_ci_va + ci_i) & (sz - 1); \ + diff = pfx##_cyc_diff(sz, old_ci, ring->ci); \ + ring->avail += diff; \ + return (diff); \ +} \ +static inline struct pfx##_entry * __unused \ +pfx##_start(struct pfx##_ring *ring, struct dpaa_portal_softc *portal) \ +{ \ + if (ring->avail <= 1) { \ + pfx##_update(ring, portal); \ + if (ring->avail == 0) \ + return (NULL); \ + } \ + dpaa_zero_line(ring->cursor); \ + return (ring->cursor); \ +} \ +static inline void __unused \ +pfx##_commit(struct pfx##_ring *ring, uint8_t verb) \ +{ \ + struct pfx##_entry *entry = ring->cursor; \ + dpaa_lw_barrier(); \ + entry->verb = verb | ring->vbit; \ + dpaa_flush_line(entry); \ + pfx##_INC(ring); \ + ring->avail--; \ +} struct hack + +#ifdef __powerpc__ +static inline void +dpaa_flush_line(void *line) +{ + __asm __volatile ("dcbf 0, %0" :: "r"(line) : "memory"); +} + +static inline void +dpaa_zero_line(void *line) +{ + __asm __volatile ("dcbz 0, %0" :: "r"(line) : "memory"); +} + +static inline void +dpaa_touch_line(void *line) +{ + __asm __volatile ("dcbt 0, %0" :: "r"(line) : "memory"); +} + +static inline void +dpaa_lw_barrier(void) +{ + powerpc_lwsync(); +} +#endif + +#endif diff --git a/sys/dev/dpaa/dpaa_eth.c b/sys/dev/dpaa/dpaa_eth.c new file mode 100644 index 000000000000..6424a6e0b0c3 --- /dev/null +++ b/sys/dev/dpaa/dpaa_eth.c @@ -0,0 +1,719 @@ +/*- + * Copyright (c) 2026 Justin Hibbits + * Copyright (c) 2012 Semihalf. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/rman.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/smp.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <sys/sysctl.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_types.h> +#include <net/if_arp.h> +#include <netinet/ip.h> +#include <netinet/ip6.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> + +#include <vm/vm.h> +#include <vm/pmap.h> + +#include "miibus_if.h" + +#include "bman.h" +#include "dpaa_common.h" +#include "dpaa_eth.h" +#include "fman.h" +#include "fman_parser.h" +#include "fman_port.h" +#include "fman_if.h" +#include "fman_port_if.h" +#include "if_dtsec.h" +#include "qman.h" +#include "qman_var.h" +#include "qman_portal_if.h" + + +#define DPAA_ETH_LOCK(sc) mtx_lock(&(sc)->sc_lock) +#define DPAA_ETH_UNLOCK(sc) mtx_unlock(&(sc)->sc_lock) +#define DPAA_ETH_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_lock, MA_OWNED) + +/** + * @group dTSEC RM private defines. + * @{ + */ +#define DTSEC_BPOOLS_USED (1) +#define DTSEC_MAX_TX_QUEUE_LEN 256 + +struct dpaa_eth_frame_info { + struct mbuf *fi_mbuf; + struct fman_internal_context fi_ic; + struct dpaa_sgte fi_sgt[DPAA_NUM_OF_SG_TABLE_ENTRY]; +}; + +enum dpaa_eth_pool_params { + DTSEC_RM_POOL_RX_LOW_MARK = 16, + DTSEC_RM_POOL_RX_HIGH_MARK = 64, + DTSEC_RM_POOL_RX_MAX_SIZE = 256, + + DTSEC_RM_POOL_FI_LOW_MARK = 16, + DTSEC_RM_POOL_FI_HIGH_MARK = 64, + DTSEC_RM_POOL_FI_MAX_SIZE = 256, +}; + +#define DTSEC_RM_FQR_RX_CHANNEL 0x401 +#define DTSEC_RM_FQR_TX_CONF_CHANNEL 0 +enum dpaa_eth_fq_params { + DTSEC_RM_FQR_RX_WQ = 1, + DTSEC_RM_FQR_TX_WQ = 1, + DTSEC_RM_FQR_TX_CONF_WQ = 1 +}; +/** @} */ + + +/** + * @group dTSEC Frame Info routines. + * @{ + */ +void +dpaa_eth_fi_pool_free(struct dpaa_eth_softc *sc) +{ + + if (sc->sc_fi_zone != NULL) + uma_zdestroy(sc->sc_fi_zone); +} + +int +dpaa_eth_fi_pool_init(struct dpaa_eth_softc *sc) +{ + + snprintf(sc->sc_fi_zname, sizeof(sc->sc_fi_zname), "%s: Frame Info", + device_get_nameunit(sc->sc_dev)); + + sc->sc_fi_zone = uma_zcreate(sc->sc_fi_zname, + sizeof(struct dpaa_eth_frame_info), NULL, NULL, NULL, NULL, + UMA_ALIGN_PTR, 0); + + return (0); +} + +static struct dpaa_eth_frame_info * +dpaa_eth_fi_alloc(struct dpaa_eth_softc *sc) +{ + struct dpaa_eth_frame_info *fi; + + fi = uma_zalloc(sc->sc_fi_zone, M_NOWAIT | M_ZERO); + + return (fi); +} + +static void +dpaa_eth_fi_free(struct dpaa_eth_softc *sc, struct dpaa_eth_frame_info *fi) +{ + + uma_zfree(sc->sc_fi_zone, fi); +} +/** @} */ + + +/** + * @group dTSEC FMan PORT routines. + * @{ + */ +int +dpaa_eth_fm_port_rx_init(struct dpaa_eth_softc *sc) +{ + struct fman_port_params params; + int error; + + params.dflt_fqid = sc->sc_rx_fqid; + params.err_fqid = sc->sc_rx_fqid; + params.rx_params.num_pools = 1; + params.rx_params.bpools[0].bpid = bman_get_bpid(sc->sc_rx_pool); + params.rx_params.bpools[0].size = MCLBYTES; + error = FMAN_PORT_CONFIG(sc->sc_rx_port, ¶ms); + error = FMAN_PORT_INIT(sc->sc_rx_port); + if (error != 0) { + device_printf(sc->sc_dev, "couldn't initialize FM Port RX.\n"); + return (ENXIO); + } + + return (0); +} + +int +dpaa_eth_fm_port_tx_init(struct dpaa_eth_softc *sc) +{ + struct fman_port_params params; + int error; + + params.dflt_fqid = sc->sc_tx_conf_fqid; + params.err_fqid = sc->sc_tx_conf_fqid; + + error = FMAN_PORT_CONFIG(sc->sc_tx_port, ¶ms); + error = FMAN_PORT_INIT(sc->sc_tx_port); + if (error != 0) { + device_printf(sc->sc_dev, "couldn't initialize FM Port TX.\n"); + return (ENXIO); + } + + return (0); +} +/** @} */ + + +/** + * @group dTSEC buffer pools routines. + * @{ + */ +static int +dpaa_eth_pool_rx_put_buffer(struct dpaa_eth_softc *sc, uint8_t *buffer, + void *context) +{ + + uma_zfree(sc->sc_rx_zone, buffer); + + return (0); +} + +static int +dtsec_add_buffers(struct dpaa_eth_softc *sc, int count) +{ + struct bman_buffer bufs[8] = {}; + int err; + int c; + + while (count > 0) { + c = min(8, count); + for (int i = 0; i < c; i++) { + void *b; + vm_paddr_t pa; + + b = uma_zalloc(sc->sc_rx_zone, M_NOWAIT); + if (b == NULL) + return (ENOMEM); + pa = pmap_kextract((vm_offset_t)b); + bufs[i].buf_hi = (pa >> 32); + bufs[i].buf_lo = (pa & 0xffffffff); + } + + err = bman_put_buffers(sc->sc_rx_pool, bufs, c); + if (err != 0) + return (err); + count -= c; + } + + return (0); +} + +static void +dpaa_eth_pool_rx_depleted(void *h_App, bool in) +{ + struct dpaa_eth_softc *sc; + unsigned int count; + + sc = h_App; + + if (!in) + return; + + while (1) { + count = bman_count(sc->sc_rx_pool); + if (count > DTSEC_RM_POOL_RX_HIGH_MARK) + return; + + /* Can only release 8 buffers at a time */ + count = min(DTSEC_RM_POOL_RX_HIGH_MARK - count + 8, 8); + if (dtsec_add_buffers(sc, count) != 0) + return; + } +} + +void +dpaa_eth_pool_rx_free(struct dpaa_eth_softc *sc) +{ + + if (sc->sc_rx_pool != NULL) + bman_pool_destroy(sc->sc_rx_pool); + + if (sc->sc_rx_zone != NULL) + uma_zdestroy(sc->sc_rx_zone); +} + +int +dpaa_eth_pool_rx_init(struct dpaa_eth_softc *sc) +{ + + /* MCLBYTES must be less than PAGE_SIZE */ + CTASSERT(MCLBYTES < PAGE_SIZE); + + snprintf(sc->sc_rx_zname, sizeof(sc->sc_rx_zname), "%s: RX Buffers", + device_get_nameunit(sc->sc_dev)); + + sc->sc_rx_zone = uma_zcreate(sc->sc_rx_zname, MCLBYTES, NULL, + NULL, NULL, NULL, MCLBYTES - 1, 0); + + sc->sc_rx_pool = bman_pool_create(&sc->sc_rx_bpid, MCLBYTES, + DTSEC_RM_POOL_RX_MAX_SIZE, DTSEC_RM_POOL_RX_LOW_MARK, + DTSEC_RM_POOL_RX_HIGH_MARK, 0, 0, dpaa_eth_pool_rx_depleted, sc); + if (sc->sc_rx_pool == NULL) { + device_printf(sc->sc_dev, "NULL rx pool somehow\n"); + dpaa_eth_pool_rx_free(sc); + return (EIO); + } + + dtsec_add_buffers(sc, DTSEC_RM_POOL_RX_HIGH_MARK); + + return (0); +} +/** @} */ + + +/** + * @group dTSEC Frame Queue Range routines. + * @{ + */ +static void +dpaa_eth_fq_mext_free(struct mbuf *m) +{ + struct dpaa_eth_softc *sc; + void *buffer; + + buffer = m->m_ext.ext_arg1; + sc = m->m_ext.ext_arg2; + if (bman_count(sc->sc_rx_pool) <= DTSEC_RM_POOL_RX_MAX_SIZE) + bman_put_buffer(sc->sc_rx_pool, + pmap_kextract((vm_offset_t)buffer), sc->sc_rx_bpid); + else + dpaa_eth_pool_rx_put_buffer(sc, buffer, NULL); +} + +static int +dpaa_eth_update_csum_flags(struct qman_fd *frame, + struct fman_parse_result *prs, struct mbuf *m) +{ + uint16_t l3r = be16toh(prs->l3r); + + /* TODO: nested protocols? */ + if ((l3r & L3R_FIRST_IP_M) != 0) { + m->m_pkthdr.csum_flags |= CSUM_L3_CALC; + if ((l3r & L3R_FIRST_ERROR) == 0) + m->m_pkthdr.csum_flags |= CSUM_L3_VALID; + } + if (frame->cmd_stat & DPAA_FD_RX_STATUS_L4CV) { + m->m_pkthdr.csum_flags |= CSUM_L4_CALC; + m->m_pkthdr.csum_data = 0xffff; + if ((prs->l4r & L4R_TYPE_M) != 0 && + (prs->l4r & L4R_ERR) == 0) + m->m_pkthdr.csum_flags |= CSUM_L4_VALID; + } + + return (0); +} + +static int +dpaa_eth_fq_rx_callback(device_t portal, struct qman_fq *fq, + struct qman_fd *frame, void *app) +{ + struct dpaa_eth_softc *sc; + struct mbuf *m; + struct fman_internal_context *frame_ic; + void *frame_va; + + m = NULL; + sc = app; + + frame_va = DPAA_FD_GET_ADDR(frame); + frame_ic = frame_va; /* internal context at head of the frame */ + /* Only simple (single- or multi-) frames are supported. */ + KASSERT(frame->format == 0 || frame->format == 4, + ("%s(): Got unsupported frame format 0x%02X!", __func__, + frame->format)); + + if ((frame->cmd_stat & DPAA_FD_CMD_STAT_ERR_M) != 0) { + device_printf(sc->sc_dev, "RX error: 0x%08X\n", + frame->cmd_stat); + goto err; + } + + m = m_gethdr(M_NOWAIT, MT_HEADER); + if (m == NULL) + goto err; + + if (frame->format == 0) { + /* Single-frame format */ + m_extadd(m, (char *)frame_va + frame->offset, frame->length, + dpaa_eth_fq_mext_free, frame_va, sc, 0, EXT_NET_DRV); + } else { + struct dpaa_sgte *sgt = + (struct dpaa_sgte *)(char *)frame_va + frame->offset; + /* Simple multi-frame format */ + for (int i = 0; i < DPAA_NUM_OF_SG_TABLE_ENTRY; i++) { + if (sgt[i].length > 0) + m_extadd(m, PHYS_TO_DMAP(sgt[i].addr), + sgt[i].length, dpaa_eth_fq_mext_free, + PHYS_TO_DMAP(sgt[i].addr), sc, 0, + EXT_NET_DRV); + if (sgt[i].final) + break; + } + /* Free the SGT buffer, it's no longer needed. */ + bman_put_buffer(sc->sc_rx_pool, frame->addr, sc->sc_rx_bpid); + } + + if (if_getcapenable(sc->sc_ifnet) & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) + dpaa_eth_update_csum_flags(frame, &frame_ic->prs, m); + + m->m_pkthdr.rcvif = sc->sc_ifnet; + m->m_len = frame->length; + m_fixhdr(m); + + if_input(sc->sc_ifnet, m); + + return (1); + +err: + bman_put_buffer(sc->sc_rx_pool, frame->addr, sc->sc_rx_bpid); + if (m != NULL) + m_freem(m); + + return (1); +} + +static int +dpaa_eth_fq_tx_confirm_callback(device_t portal, struct qman_fq *fq, + struct qman_fd *frame, void *app) +{ + struct dpaa_eth_frame_info *fi; + struct dpaa_eth_softc *sc; + unsigned int qlen; + struct dpaa_sgte *sgt0; + + sc = app; + + if ((frame->cmd_stat & DPAA_FD_TX_STAT_ERR_M) != 0) + device_printf(sc->sc_dev, "TX error: 0x%08X\n", + frame->cmd_stat); + + /* + * We are storing struct dpaa_eth_frame_info in first entry + * of scatter-gather table. + */ + sgt0 = (struct dpaa_sgte *)PHYS_TO_DMAP(frame->addr + frame->offset); + fi = (struct dpaa_eth_frame_info *)PHYS_TO_DMAP(sgt0->addr); + + /* Free transmitted frame */ + m_freem(fi->fi_mbuf); + dpaa_eth_fi_free(sc, fi); + + qlen = qman_fq_get_counter(sc->sc_tx_conf_fq, QMAN_COUNTER_FRAME); + + if (qlen == 0) { + DPAA_ETH_LOCK(sc); + + if (sc->sc_tx_fq_full) { + sc->sc_tx_fq_full = 0; + dpaa_eth_if_start_locked(sc); + } + + DPAA_ETH_UNLOCK(sc); + } + + return (1); +} + +void +dpaa_eth_fq_rx_free(struct dpaa_eth_softc *sc) +{ + int cpu; + + if (sc->sc_rx_fq) + qman_fq_free(sc->sc_rx_fq); + if (sc->sc_rx_channel != 0) { + CPU_FOREACH(cpu) { + device_t portal = DPCPU_ID_GET(cpu, qman_affine_portal); + QMAN_PORTAL_STATIC_DEQUEUE_RM_CHANNEL(portal, + sc->sc_rx_channel); + } + qman_free_channel(sc->sc_rx_channel); + } +} + +int +dpaa_eth_fq_rx_init(struct dpaa_eth_softc *sc) +{ + void *fq; + int error; + int cpu; + + /* Default Frame Queue */ + if (sc->sc_rx_channel == 0) + sc->sc_rx_channel = qman_alloc_channel(); + fq = qman_fq_create(1, sc->sc_rx_channel, DTSEC_RM_FQR_RX_WQ, + false, 0, false, false, true, false, 0, 0, 0); + if (fq == NULL) { + device_printf(sc->sc_dev, + "could not create default RX queue\n"); + return (EIO); + } + + CPU_FOREACH(cpu) { + device_t portal = DPCPU_ID_GET(cpu, qman_affine_portal); + QMAN_PORTAL_STATIC_DEQUEUE_CHANNEL(portal, sc->sc_rx_channel); + } + + sc->sc_rx_fq = fq; + sc->sc_rx_fqid = qman_fq_get_fqid(fq); + + error = qman_fq_register_cb(fq, dpaa_eth_fq_rx_callback, sc); + if (error != 0) { + device_printf(sc->sc_dev, "could not register RX callback\n"); + dpaa_eth_fq_rx_free(sc); + return (EIO); + } + + return (0); +} + +void +dpaa_eth_fq_tx_free(struct dpaa_eth_softc *sc) +{ + + if (sc->sc_tx_fq) + qman_fq_free(sc->sc_tx_fq); + + if (sc->sc_tx_conf_fq) + qman_fq_free(sc->sc_tx_conf_fq); +} + +int +dpaa_eth_fq_tx_init(struct dpaa_eth_softc *sc) +{ + int error; + void *fq; + + /* TX Frame Queue */ + fq = qman_fq_create(1, sc->sc_port_tx_qman_chan, + DTSEC_RM_FQR_TX_WQ, false, 0, false, false, true, false, 0, 0, 0); + if (fq == NULL) { + device_printf(sc->sc_dev, "could not create default TX queue" + "\n"); + return (EIO); + } + + sc->sc_tx_fq = fq; + + if (sc->sc_rx_channel == 0) + sc->sc_rx_channel = qman_alloc_channel(); + /* TX Confirmation Frame Queue */ + fq = qman_fq_create(1, sc->sc_rx_channel, + DTSEC_RM_FQR_TX_CONF_WQ, false, 0, false, false, true, false, 0, 0, + 0); + if (fq == NULL) { + device_printf(sc->sc_dev, "could not create TX confirmation " + "queue\n"); + dpaa_eth_fq_tx_free(sc); + return (EIO); + } + + sc->sc_tx_conf_fq = fq; + sc->sc_tx_conf_fqid = qman_fq_get_fqid(fq); + + error = qman_fq_register_cb(fq, dpaa_eth_fq_tx_confirm_callback, sc); + if (error != 0) { + device_printf(sc->sc_dev, "could not register TX confirmation " + "callback\n"); + dpaa_eth_fq_tx_free(sc); + return (EIO); + } + + return (0); +} +/** @} */ + +/* Returns the cmd_stat field for the frame descriptor */ +static uint32_t +dpaa_eth_tx_add_csum(struct dpaa_eth_frame_info *fi) +{ + struct mbuf *m = fi->fi_mbuf; + struct fman_parse_result *prs = &fi->fi_ic.prs; + uint32_t csum_flags = m->m_pkthdr.csum_flags; + uint8_t ether_size = ETHER_HDR_LEN; + + if ((csum_flags & CSUM_FLAGS_TX) == 0) + return (0); + + if (m->m_flags & M_VLANTAG) + ether_size += ETHER_VLAN_ENCAP_LEN; + if (csum_flags & CSUM_IP) + prs->l3r = L3R_FIRST_IPV4; + if (csum_flags & CSUM_IP_UDP) { + prs->l4r = L4R_TYPE_UDP; + prs->l4_off = ether_size + sizeof(struct ip); + } else if (csum_flags & CSUM_IP_TCP) { + prs->l4r = L4R_TYPE_TCP; + prs->l4_off = ether_size + sizeof(struct ip); + } else if (csum_flags & CSUM_IP6_UDP) { + prs->l3r = L3R_FIRST_IPV6; + prs->l4r = L4R_TYPE_UDP; + prs->l4_off = ether_size + sizeof(struct ip6_hdr); + } else if (csum_flags & CSUM_IP6_TCP) { + prs->l3r = L3R_FIRST_IPV6; + prs->l4r = L4R_TYPE_TCP; + prs->l4_off = ether_size + sizeof(struct ip6_hdr); + } + + prs->ip_off[0] = ether_size; + + return (DPAA_FD_TX_CMD_RPD | DPAA_FD_TX_CMD_DTC); +} + +/** + * @group dTSEC IFnet routines. + * @{ + */ +void +dpaa_eth_if_start_locked(struct dpaa_eth_softc *sc) +{ + vm_size_t dsize, psize, ssize; + struct dpaa_eth_frame_info *fi; + unsigned int qlen, i; + struct mbuf *m0, *m; + vm_offset_t vaddr; + struct dpaa_fd fd; + + DPAA_ETH_LOCK_ASSERT(sc); + /* TODO: IFF_DRV_OACTIVE */ + + if ((sc->sc_mii->mii_media_status & IFM_ACTIVE) == 0) + return; + + if ((if_getdrvflags(sc->sc_ifnet) & IFF_DRV_RUNNING) != IFF_DRV_RUNNING) + return; + + while (!if_sendq_empty(sc->sc_ifnet)) { + /* Check length of the TX queue */ + qlen = qman_fq_get_counter(sc->sc_tx_fq, QMAN_COUNTER_FRAME); + + if (qlen >= DTSEC_MAX_TX_QUEUE_LEN) { + sc->sc_tx_fq_full = 1; + return; + } + + fi = dpaa_eth_fi_alloc(sc); + if (fi == NULL) + return; + + m0 = if_dequeue(sc->sc_ifnet); + if (m0 == NULL) { + dpaa_eth_fi_free(sc, fi); + return; + } + + i = 0; + m = m0; + psize = 0; + dsize = 0; + fi->fi_mbuf = m0; + while (m && i < DPAA_NUM_OF_SG_TABLE_ENTRY) { + if (m->m_len == 0) + continue; + + /* + * First entry in scatter-gather table is used to keep + * pointer to frame info structure. + */ + fi->fi_sgt[i].addr = pmap_kextract((vm_offset_t)fi); + i++; + + dsize = m->m_len; + vaddr = (vm_offset_t)m->m_data; + while (dsize > 0 && i < DPAA_NUM_OF_SG_TABLE_ENTRY) { + ssize = PAGE_SIZE - (vaddr & PAGE_MASK); + if (m->m_len < ssize) + ssize = m->m_len; + + fi->fi_sgt[i].addr = pmap_kextract(vaddr); + fi->fi_sgt[i].length = ssize; + + fi->fi_sgt[i].extension = 0; + fi->fi_sgt[i].final = 0; + fi->fi_sgt[i].bpid = 0; + fi->fi_sgt[i].offset = 0; + + dsize -= ssize; + vaddr += ssize; + psize += ssize; + i++; + } + + if (dsize > 0) + break; + + m = m->m_next; + } + + /* Check if SG table was constructed properly */ + if (m != NULL || dsize != 0) { + dpaa_eth_fi_free(sc, fi); + m_freem(m0); + continue; + } + + fi->fi_sgt[i - 1].final = 1; + + fd.addr = pmap_kextract((vm_offset_t)&fi->fi_ic); + fd.length = psize; + fd.format = DPAA_FD_FORMAT_SHORT_MBSF; + + fd.liodn = 0; + fd.bpid = 0; + fd.eliodn = 0; + fd.offset = offsetof(struct dpaa_eth_frame_info, fi_sgt) - + offsetof(struct dpaa_eth_frame_info, fi_ic); + fd.cmd_stat = dpaa_eth_tx_add_csum(fi); + + DPAA_ETH_UNLOCK(sc); + if (qman_fq_enqueue(sc->sc_tx_fq, &fd) != 0) { + dpaa_eth_fi_free(sc, fi); + m_freem(m0); + } + DPAA_ETH_LOCK(sc); + } +} +/** @} */ diff --git a/sys/dev/dpaa/dpaa_eth.h b/sys/dev/dpaa/dpaa_eth.h new file mode 100644 index 000000000000..7832b4dd7bff --- /dev/null +++ b/sys/dev/dpaa/dpaa_eth.h @@ -0,0 +1,116 @@ +/*- + * Copyright (c) 2012 Semihalf. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef DPAA_ETH_H_ +#define DPAA_ETH_H_ + +struct dpaa_eth_softc { + /* XXX MII bus requires that struct ifnet is first!!! */ + if_t sc_ifnet; + + device_t sc_dev; + struct resource *sc_mem; + struct mtx sc_lock; + + int sc_mac_enet_mode; + + /* RX Pool */ + struct bman_pool *sc_rx_pool; + uint8_t sc_rx_bpid; + uma_zone_t sc_rx_zone; + char sc_rx_zname[64]; + + /* RX Frame Queue */ + struct qman_fq *sc_rx_fq; + uint32_t sc_rx_fqid; + + /* TX Frame Queue */ + struct qman_fq *sc_tx_fq; + bool sc_tx_fq_full; + struct qman_fq *sc_tx_conf_fq; + uint32_t sc_tx_conf_fqid; + + /* Methods */ + int (*sc_port_rx_init) + (struct dpaa_eth_softc *sc, int unit); + int (*sc_port_tx_init) + (struct dpaa_eth_softc *sc, int unit); + void (*sc_start_locked) + (struct dpaa_eth_softc *sc); + + /* dTSEC data */ + uint8_t sc_eth_id; /* Ethernet ID within its frame manager */ + uintptr_t sc_mac_mem_offset; + int sc_mac_mdio_irq; + uint8_t sc_mac_addr[6]; + int sc_port_rx_hw_id; + int sc_port_tx_hw_id; + uint32_t sc_port_tx_qman_chan; + int sc_phy_addr; + bool sc_hidden; + device_t sc_mdio; + int sc_rev_major; + int sc_rev_minor; + + device_t sc_rx_port; + device_t sc_tx_port; + + int sc_rx_channel; + + /* MII data */ + struct mii_data *sc_mii; + device_t sc_mii_dev; + struct mtx sc_mii_lock; + + struct callout sc_tick_callout; + + /* Frame Info Zone */ + uma_zone_t sc_fi_zone; + char sc_fi_zname[64]; +}; + +/** + * @group dTSEC Regular Mode API. + * @{ + */ +int dpaa_eth_fm_port_rx_init(struct dpaa_eth_softc *sc); +int dpaa_eth_fm_port_tx_init(struct dpaa_eth_softc *sc); + +void dpaa_eth_if_start_locked(struct dpaa_eth_softc *sc); + +int dpaa_eth_pool_rx_init(struct dpaa_eth_softc *sc); +void dpaa_eth_pool_rx_free(struct dpaa_eth_softc *sc); + +int dpaa_eth_fi_pool_init(struct dpaa_eth_softc *sc); +void dpaa_eth_fi_pool_free(struct dpaa_eth_softc *sc); + +int dpaa_eth_fq_rx_init(struct dpaa_eth_softc *sc); +int dpaa_eth_fq_tx_init(struct dpaa_eth_softc *sc); +void dpaa_eth_fq_rx_free(struct dpaa_eth_softc *sc); +void dpaa_eth_fq_tx_free(struct dpaa_eth_softc *sc); +/** @} */ + +#endif /* DPAA_ETH_H_ */ diff --git a/sys/dev/dpaa/fman.c b/sys/dev/dpaa/fman.c index 393c28487ba9..b94c05fd7dbf 100644 --- a/sys/dev/dpaa/fman.c +++ b/sys/dev/dpaa/fman.c @@ -1,27 +1,7 @@ -/*- - * Copyright (c) 2011-2012 Semihalf. - * All rights reserved. +/* + * Copyright (c) 2026 Justin Hibbits * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * SPDX-License-Identifier: BSD-2-Clause */ #include <sys/param.h> @@ -33,6 +13,7 @@ #include <sys/malloc.h> #include <dev/fdt/simplebus.h> +#include <dev/fdt/fdt_common.h> #include <dev/ofw/ofw_bus.h> #include <dev/ofw/ofw_bus_subr.h> @@ -40,50 +21,140 @@ #include "opt_platform.h" -#include <contrib/ncsw/inc/Peripherals/fm_ext.h> -#include <contrib/ncsw/inc/Peripherals/fm_muram_ext.h> -#include <contrib/ncsw/inc/ncsw_ext.h> -#include <contrib/ncsw/integrations/fman_ucode.h> +#include <powerpc/mpc85xx/mpc85xx.h> #include "fman.h" +#define FMAN_BMI_OFFSET 0x80000 +#define FMAN_QMI_OFFSET 0x80400 +#define FMAN_KG_OFFSET 0xc1000 +#define FMAN_DMA_OFFSET 0xc2000 +#define FMAN_FPM_OFFSET 0xc3000 +#define FMAN_IMEM_OFFSET 0xc4000 +#define FMAN_HWP_OFFSET 0xc7000 +#define FMAN_CGP_OFFSET 0xdb000 + +#define FM_IP_REV_1 (FMAN_FPM_OFFSET + 0x0c4) +#define IP_REV_1_MAJ_M 0x0000ff00 +#define IP_REV_1_MAJ_S 8 +#define IP_REV_1_MIN_M 0x000000ff +#define FM_RSTC (FMAN_FPM_OFFSET + 0x0cc) +#define FM_RSTC_FM_RESET 0x80000000 + +#define FMBM_INIT (FMAN_BMI_OFFSET + 0x000) +#define INIT_STR 0x80000000 +#define FMBM_CFG1 (FMAN_BMI_OFFSET + 0x0004) +#define FBPS_M 0x07ff0000 +#define FBPS_S 16 +#define FBPO_M 0x000007ff +#define FMBM_CFG2 (FMAN_BMI_OFFSET + 0x0008) +#define TNTSKS_M 0x007f0000 +#define TNTSKS_S 16 +#define FMBM_IEVR (FMAN_BMI_OFFSET + 0x0020) +#define IEVR_SPEC 0x80000000 +#define IEVR_LEC 0x40000000 +#define IEVR_STEC 0x20000000 +#define IEVR_DEC 0x10000000 +#define FMBM_IER (FMAN_BMI_OFFSET + 0x0024) +#define IER_SPECE 0x80000000 +#define IER_LECE 0x40000000 +#define IER_STECE 0x20000000 +#define IER_DECE 0x10000000 +#define FMBM_PP(n) (FMAN_BMI_OFFSET + 0x104 + ((n - 1) * 4)) +#define PP_MXT_M 0x3f000000 +#define PP_MXT_S 24 +#define PP_EXT_M 0x000f0000 +#define PP_EXT_S 16 +#define PP_MXD_M 0x00000f00 +#define PP_MXD_S 8 +#define PP_EXD_M 0x0000000f +#define FMBM_PFS(n) (FMAN_BMI_OFFSET + 0x204 + ((n - 1) * 4)) +#define PFS_EXBS_M 0x03ff0000 +#define PFS_EXBS_S 16 +#define PFS_IFSZ_M 0x000003ff +#define FMQM_GC (FMAN_QMI_OFFSET + 0x000) +#define GC_STEN 0x10000000 +#define GC_ENQ_THR_S 8 +#define GC_ENQ_THR_M 0x00003f00 +#define GC_DEQ_THR_M 0x0000003f +#define FMQM_EIE (FMAN_QMI_OFFSET + 0x008) +#define EIE_DEE 0x80000000 +#define EIE_DFUPE 0x40000000 +#define FMQM_EIEN (FMAN_QMI_OFFSET + 0x00c) +#define EIEN_DEE 0x80000000 +#define EIEN_DFUPE 0x40000000 +#define FMQM_IE +#define IRAM_ADDR (FMAN_IMEM_OFFSET + 0x000) +#define IADD_AIE 0x80000000 +#define IRAM_DATA (FMAN_IMEM_OFFSET + 0x004) +#define IRAM_READY (FMAN_IMEM_OFFSET + 0x0c) +#define IREADY_READY 0x80000000 + +#define FMPR_RPIMAC (FMAN_HWP_OFFSET + 0x844) +#define HWP_RPIMAC_PEN 0x00000001 + +#define FMDM_SR (FMAN_DMA_OFFSET + 0x000) +#define SR_CMDQNE 0x10000000 +#define SR_BER 0x08000000 +#define SR_RDB_ECC 0x04000000 +#define SR_WRB_SECC 0x02000000 +#define FMDM_MR (FMAN_DMA_OFFSET + 0x004) +#define MR_CEN_M 0x0000e000 +#define MR_CEN_S 13 +#define FMDM_SETR (FMAN_DMA_OFFSET + 0x010) +#define FMDM_EBCR (FMAN_DMA_OFFSET + 0x2c) +#define FMDM_PLRn(n) (FMAN_DMA_OFFSET + 0x060 + (4 * (n / 2))) +#define PLRN_LIODN_M(n) (0xfff << PLRN_LIODN_S(n)) +#define PLRN_LIODN_S(n) ((n & 1) ? 0 : 16) + +#define FMFP_TSC1 (FMAN_FPM_OFFSET + 0x060) +#define TSC1_TEN 0x80000000 +#define FMFP_TSC2 (FMAN_FPM_OFFSET + 0x064) +#define TSC2_TSIV_INT_S 16 +#define FM_RCR (FMAN_FPM_OFFSET + 0x070) +#define RCR_FEE 0x80000000 +#define RCR_IEE 0x40000000 +#define RCR_MET 0x20000000 +#define RCR_IET 0x10000000 +#define RCR_SFE 0x08000000 +#define FMFP_EE (FMAN_FPM_OFFSET + 0x0dc) +#define EE_DECC 0x80000000 +#define EE_STL 0x40000000 +#define EE_SECC 0x20000000 +#define EE_RFM 0x00010000 +#define EE_DECC_EN 0x00008000 +#define EE_STL_EN 0x00004000 +#define EE_SECC_EN 0x00002000 +#define EE_EHM 0x00000008 +#define EE_CER 0x00000002 +#define EE_DER 0x00000001 +#define FMFP_CEV0 (FMAN_FPM_OFFSET + 0x0e0) +#define FMFP_CEV1 (FMAN_FPM_OFFSET + 0x0e4) +#define FMFP_CEV2 (FMAN_FPM_OFFSET + 0x0e8) +#define FMFP_CEV3 (FMAN_FPM_OFFSET + 0x0ec) + +/* DMA constants */ +#define DMA_CAM_UNITS 8 +#define DMA_CAM_SIZE 64 +#define DMA_CAM_ALIGN 64 + + +/* Timestamp counter */ +#define FM_TIMESTAMP_1US_BIT 8 static MALLOC_DEFINE(M_FMAN, "fman", "fman devices information"); +static void fman_intr(void *arg); + /** * @group FMan private defines. * @{ */ -enum fman_irq_enum { - FMAN_IRQ_NUM = 0, - FMAN_ERR_IRQ_NUM = 1 -}; - -enum fman_mu_ram_map { - FMAN_MURAM_OFF = 0x0, - FMAN_MURAM_SIZE = 0x28000 -}; - -struct fman_config { - device_t fman_device; - uintptr_t mem_base_addr; - uintptr_t irq_num; - uintptr_t err_irq_num; - uint8_t fm_id; - t_FmExceptionsCallback *exception_callback; - t_FmBusErrorCallback *bus_error_callback; -}; /** * @group FMan private methods/members. * @{ */ -/** - * Frame Manager firmware. - * We use the same firmware for both P3041 and P2041 devices. - */ -const uint32_t fman_firmware[] = FMAN_UC_IMG; -const uint32_t fman_firmware_size = sizeof(fman_firmware); int fman_activate_resource(device_t bus, device_t child, struct resource *res) @@ -125,7 +196,7 @@ fman_release_resource(device_t bus, device_t child, struct resource *res) passthrough = (device_get_parent(child) != bus); rl = BUS_GET_RESOURCE_LIST(bus, child); if (rman_get_type(res) != SYS_RES_IRQ) { - if ((rman_get_flags(res) & RF_ACTIVE) != 0 ){ + if ((rman_get_flags(res) & RF_ACTIVE) != 0) { rv = bus_deactivate_resource(child, res); if (rv != 0) return (rv); @@ -209,202 +280,400 @@ fman_alloc_resource(device_t bus, device_t child, int type, int rid, return (NULL); } + static int -fman_fill_ranges(phandle_t node, struct simplebus_softc *sc) +fman_get_revision_major(struct fman_softc *sc) { - int host_address_cells; - cell_t *base_ranges; - ssize_t nbase_ranges; - int err; - int i, j, k; + uint32_t reg; - err = OF_searchencprop(OF_parent(node), "#address-cells", - &host_address_cells, sizeof(host_address_cells)); - if (err <= 0) - return (-1); + reg = bus_read_4(sc->mem_res, FM_IP_REV_1); - nbase_ranges = OF_getproplen(node, "ranges"); - if (nbase_ranges < 0) - return (-1); - sc->nranges = nbase_ranges / sizeof(cell_t) / - (sc->acells + host_address_cells + sc->scells); - if (sc->nranges == 0) - return (0); + return ((reg & IP_REV_1_MAJ_M) >> IP_REV_1_MAJ_S); +} - sc->ranges = malloc(sc->nranges * sizeof(sc->ranges[0]), - M_DEVBUF, M_WAITOK); - base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK); - OF_getencprop(node, "ranges", base_ranges, nbase_ranges); +static int +fman_get_revision_minor(struct fman_softc *sc) +{ + uint32_t reg; - for (i = 0, j = 0; i < sc->nranges; i++) { - sc->ranges[i].bus = 0; - for (k = 0; k < sc->acells; k++) { - sc->ranges[i].bus <<= 32; - sc->ranges[i].bus |= base_ranges[j++]; - } - sc->ranges[i].host = 0; - for (k = 0; k < host_address_cells; k++) { - sc->ranges[i].host <<= 32; - sc->ranges[i].host |= base_ranges[j++]; - } - sc->ranges[i].size = 0; - for (k = 0; k < sc->scells; k++) { - sc->ranges[i].size <<= 32; - sc->ranges[i].size |= base_ranges[j++]; + reg = bus_read_4(sc->mem_res, FM_IP_REV_1); + + return ((reg & IP_REV_1_MIN_M)); +} + +static void +fman_fill_soc_params(struct fman_softc *sc) +{ + + switch (sc->sc_revision_major) { + case 2: + sc->bmi_max_fifo_size = 160 * 1024; + sc->iram_size = 64 * 1024; + sc->dma_thresh_max_commq = 31; + sc->dma_thresh_max_buf = 127; + sc->qmi_max_tnums = 64; + sc->qmi_def_tnums_thresh = 48; + sc->bmi_max_tasks = 128; + sc->max_open_dmas = 32; + sc->dma_cam_num_entries = 32; + sc->port_cgs = 256; + sc->rx_ports = 5; + sc->total_fifo_size = 100 * 1024; + break; + case 3: + sc->bmi_max_fifo_size = 160 * 1024; + sc->iram_size = 64 * 1024; + sc->dma_thresh_max_commq = 31; + sc->dma_thresh_max_buf = 127; + sc->qmi_max_tnums = 64; + sc->qmi_def_tnums_thresh = 48; + sc->bmi_max_tasks = 128; + sc->max_open_dmas = 32; + sc->dma_cam_num_entries = 32; + sc->port_cgs = 256; + sc->rx_ports = 6; + sc->total_fifo_size = 136 * 1024; + break; + case 6: + sc->dma_thresh_max_commq = 31; + sc->dma_thresh_max_buf = 127; + sc->qmi_max_tnums = 64; + sc->qmi_def_tnums_thresh = 48; + sc->dma_cam_num_entries = 64; + sc->port_cgs = 256; + switch (sc->sc_revision_minor) { + case 1: + case 4: + sc->bmi_max_fifo_size = 192 * 1024; + sc->bmi_max_tasks = 64; + sc->max_open_dmas = 32; + sc->rx_ports = 5; + sc->total_fifo_size = 156 * 1024; + if (sc->sc_revision_minor == 1) + sc->iram_size = 32 * 1024; + else + sc->iram_size = 64 * 1024; + break; + case 0: + case 2: + case 3: + sc->bmi_max_fifo_size = 384 * 1024; + sc->bmi_max_tasks = 128; + sc->max_open_dmas = 84; + sc->rx_ports = 8; + sc->iram_size = 64 * 1024; + sc->total_fifo_size = 295 * 1024; + break; + default: + device_printf(sc->sc_base.dev, + "Unsupported FManv3 revision: %d\n", + sc->sc_revision_minor); + break; } + break; + default: + device_printf(sc->sc_base.dev, + "Unsupported FMan version: %d\n", sc->sc_revision_major); + break; } - - free(base_ranges, M_DEVBUF); - return (sc->nranges); } -static t_Handle -fman_init(struct fman_softc *sc, struct fman_config *cfg) +static int +fman_reset(struct fman_softc *sc) { - phandle_t node; - t_FmParams fm_params; - t_Handle muram_handle, fm_handle; - t_Error error; - t_FmRevisionInfo revision_info; - uint16_t clock; - uint32_t tmp, mod; + unsigned int count; + + if (sc->sc_revision_major < 6) { + bus_write_4(sc->mem_res, FM_RSTC, FM_RSTC_FM_RESET); + count = 100; + do { + DELAY(1); + } while ((bus_read_4(sc->mem_res, FM_RSTC) & FM_RSTC_FM_RESET) && + --count); + if (count == 0) + return (EBUSY); + return (0); + } else { +#ifdef __powerpc__ + phandle_t node; + u_long base, size; + uint32_t devdisr2; +#define GUTS_DEVDISR2 0x0074 +#define DEVDISR2_FMAN1 0xfcc00000 +#define DEVDISR2_FMAN2 0x000fcc00 + + node = ofw_bus_get_node(device_get_parent(sc->sc_base.dev)); + node = fdt_find_compatible(node, "fsl,qoriq-device-config-2.0", + false); - /* MURAM configuration */ - muram_handle = FM_MURAM_ConfigAndInit(cfg->mem_base_addr + - FMAN_MURAM_OFF, FMAN_MURAM_SIZE); - if (muram_handle == NULL) { - device_printf(cfg->fman_device, "couldn't init FM MURAM module" - "\n"); - return (NULL); + if (node == 0) { + device_printf(sc->sc_base.dev, + "missing device-config node in FDT. Cannot reset FMAN"); + return (0); + } + fdt_regsize(node, &base, &size); + + devdisr2 = ccsr_read4(ccsrbar_va + base + GUTS_DEVDISR2); + if (sc->fm_id == 0) + ccsr_write4(ccsrbar_va + base + GUTS_DEVDISR2, + devdisr2 & ~DEVDISR2_FMAN1); + else + ccsr_write4(ccsrbar_va + base + GUTS_DEVDISR2, + devdisr2 & ~DEVDISR2_FMAN2); +#endif + bus_write_4(sc->mem_res, FM_RSTC, FM_RSTC_FM_RESET); + count = 100; + do { + DELAY(1); + } while ((bus_read_4(sc->mem_res, FM_RSTC) & FM_RSTC_FM_RESET) && + --count); +#ifdef __powerpc__ + ccsr_write4(ccsrbar_va + base + GUTS_DEVDISR2, devdisr2); +#endif + if (count == 0) + return (EBUSY); + return (0); } - sc->muram_handle = muram_handle; +} - /* Fill in FM configuration */ - fm_params.fmId = cfg->fm_id; - /* XXX we support only one partition thus each fman has master id */ - fm_params.guestId = NCSW_MASTER_ID; +static int +fman_clear_iram(struct fman_softc *sc) +{ +#ifdef notyet + int i; - fm_params.baseAddr = cfg->mem_base_addr; - fm_params.h_FmMuram = muram_handle; + /* + * TODO: Allow clearing the IRAM and loading new firmware. Currently + * this is not supported, so assume that there's already firmware + * loaded, and don't clear it just yet. + */ + bus_write_4(sc->mem_res, IRAM_ADDR, IADD_AIE); + for (i = 0; i < 100 && bus_read_4(sc->mem_res, IRAM_ADDR) != IADD_AIE; i++) + DELAY(1); - /* Get FMan clock in Hz */ - if ((tmp = fman_get_clock(sc)) == 0) - return (NULL); + if (i == 100) + return (EBUSY); - /* Convert FMan clock to MHz */ - clock = (uint16_t)(tmp / 1000000); - mod = tmp % 1000000; + for (i = 0; i < sc->iram_size / 4; i++) + bus_write_4(sc->mem_res, IRAM_DATA, 0xffffffff); - if (mod >= 500000) - ++clock; + bus_write_4(sc->mem_res, IRAM_ADDR, sc->iram_size - 4); + for (i = 0; i < 100 && + bus_read_4(sc->mem_res, IRAM_DATA) != 0xffffffff; i++) + DELAY(1); - fm_params.fmClkFreq = clock; - fm_params.f_Exception = cfg->exception_callback; - fm_params.f_BusError = cfg->bus_error_callback; - fm_params.h_App = cfg->fman_device; - fm_params.irq = cfg->irq_num; - fm_params.errIrq = cfg->err_irq_num; + if (i == 100) + return (EBUSY); +#endif - fm_params.firmware.size = fman_firmware_size; - fm_params.firmware.p_Code = (uint32_t*)fman_firmware; + return (0); +} - fm_handle = FM_Config(&fm_params); - if (fm_handle == NULL) { - device_printf(cfg->fman_device, "couldn't configure FM " - "module\n"); - goto err; - } +static int +fman_dma_init(struct fman_softc *sc) +{ + vmem_addr_t addr; + uint32_t reg; + int err; - FM_ConfigResetOnInit(fm_handle, TRUE); + reg = bus_read_4(sc->mem_res, FMDM_SR); + bus_write_4(sc->mem_res, FMDM_SR, reg | SR_BER); + reg = bus_read_4(sc->mem_res, FMDM_MR) & ~MR_CEN_M; + reg |= ((sc->dma_cam_num_entries / DMA_CAM_UNITS) - 1) << MR_CEN_S; + bus_write_4(sc->mem_res, FMDM_MR, reg); - error = FM_Init(fm_handle); - if (error != E_OK) { - device_printf(cfg->fman_device, "couldn't init FM module\n"); - goto err2; - } + err = vmem_xalloc(sc->muram_vmem, + sc->dma_cam_num_entries * DMA_CAM_SIZE, DMA_CAM_ALIGN, 0, 0, + VMEM_ADDR_MIN, VMEM_ADDR_MAX, M_BESTFIT | M_WAITOK, &addr); + if (err != 0) + device_printf(sc->sc_base.dev, + "failed to allocate DMA buffer\n"); + reg = addr; + bus_write_4(sc->mem_res, FMDM_EBCR, reg); + return (0); +} - error = FM_GetRevision(fm_handle, &revision_info); - if (error != E_OK) { - device_printf(cfg->fman_device, "couldn't get FM revision\n"); - goto err2; - } +static int +fman_bmi_init(struct fman_softc *sc) +{ + uint32_t reg; - device_printf(cfg->fman_device, "Hardware version: %d.%d.\n", - revision_info.majorRev, revision_info.minorRev); + reg = sc->bmi_fifo_base / FMAN_BMI_FIFO_ALIGN; + reg |= (sc->total_fifo_size / FMAN_BMI_FIFO_UNITS - 1) << FBPS_S; + bus_write_4(sc->mem_res, FMBM_CFG1, reg); - /* Initialize the simplebus part of things */ - simplebus_init(sc->sc_base.dev, 0); + reg = ((sc->bmi_max_tasks - 1) << TNTSKS_S) & TNTSKS_M; + //bus_write_4(sc->mem_res, FMBM_CFG2, reg); - node = ofw_bus_get_node(sc->sc_base.dev); - fman_fill_ranges(node, &sc->sc_base); - sc->rman.rm_type = RMAN_ARRAY; - sc->rman.rm_descr = "FMan range"; - rman_init_from_resource(&sc->rman, sc->mem_res); - for (node = OF_child(node); node > 0; node = OF_peer(node)) { - simplebus_add_device(sc->sc_base.dev, node, 0, NULL, -1, NULL); - } + bus_write_4(sc->mem_res, FMBM_IEVR, + IEVR_SPEC | IEVR_LEC | IEVR_STEC | IEVR_DEC); - return (fm_handle); + bus_write_4(sc->mem_res, FMBM_IER, + IER_SPECE | IER_LECE | IER_STECE | IER_DECE); -err2: - FM_Free(fm_handle); -err: - FM_MURAM_Free(muram_handle); - return (NULL); + return (0); } -static void -fman_exception_callback(t_Handle app_handle, e_FmExceptions exception) +static int +fman_qmi_init(struct fman_softc *sc) { - struct fman_softc *sc; - - sc = app_handle; - device_printf(sc->sc_base.dev, "FMan exception occurred.\n"); + bus_write_4(sc->mem_res, FMQM_EIE, EIE_DEE | EIE_DFUPE); + bus_write_4(sc->mem_res, FMQM_EIEN, EIEN_DEE | EIEN_DFUPE); + return (0); } static void -fman_error_callback(t_Handle app_handle, e_FmPortType port_type, - uint8_t port_id, uint64_t addr, uint8_t tnum, uint16_t liodn) +fman_hwp_init(struct fman_softc *sc) { - struct fman_softc *sc; - - sc = app_handle; - device_printf(sc->sc_base.dev, "FMan error occurred.\n"); + /* Start up the parser */ + bus_write_4(sc->mem_res, FMPR_RPIMAC, HWP_RPIMAC_PEN); } -/** @} */ +static int +fman_enable(struct fman_softc *sc) +{ + bus_write_4(sc->mem_res, FMBM_INIT, INIT_STR); + bus_write_4(sc->mem_res, FMQM_GC, 0xc0000000 | + GC_STEN | (sc->qmi_def_tnums_thresh << GC_ENQ_THR_S) | + sc->qmi_def_tnums_thresh); -/** - * @group FMan driver interface. - * @{ + return (0); +} + +/* + * Enable timestamp counting. Matching Freescale's reference code, generate the + * timestamp incrementer to be roughly 256MHz, such that bit 23 would update + * every microsecond. */ +static int +fman_enable_timestamp(struct fman_softc *sc) +{ + uint64_t frac; + uint32_t clock = fman_get_clock(sc) / 1000000; + uint32_t intgr, tmp; + uint32_t ts_freq = 1 << FM_TIMESTAMP_1US_BIT; -int -fman_get_handle(device_t dev, t_Handle *fmh) + intgr = ts_freq / clock; + + frac = ((uint64_t)ts_freq << 16) - ((uint64_t)intgr << 16) * clock; + frac = (frac % clock ? 1 : 0) + (frac / clock); + + tmp = (intgr << TSC2_TSIV_INT_S) | (uint32_t)frac; + + bus_write_4(sc->mem_res, FMFP_TSC2, tmp); + bus_write_4(sc->mem_res, FMFP_TSC1, TSC1_TEN); + + return (0); +} + +static int +fman_keygen_init(struct fman_softc *sc) { - struct fman_softc *sc = device_get_softc(dev); + /* TODO: keygen */ + return (0); +} + +static int +fman_fpm_init(struct fman_softc *sc) +{ + /* Clear all events, and enable interrupts. */ + bus_write_4(sc->mem_res, FMFP_EE, + EE_DECC | EE_STL | EE_SECC | EE_EHM | + EE_DECC_EN | EE_STL_EN | EE_SECC_EN); + + bus_write_4(sc->mem_res, FMFP_CEV0, 0xffffffff); + bus_write_4(sc->mem_res, FMFP_CEV1, 0xffffffff); + bus_write_4(sc->mem_res, FMFP_CEV2, 0xffffffff); + bus_write_4(sc->mem_res, FMFP_CEV3, 0xffffffff); - *fmh = sc->fm_handle; + bus_write_4(sc->mem_res, FM_RCR, RCR_FEE | RCR_IEE); return (0); } -int -fman_get_muram_handle(device_t dev, t_Handle *muramh) +static int +fman_init(struct fman_softc *sc) { - struct fman_softc *sc = device_get_softc(dev); + vmem_addr_t base_addr; + sc->sc_revision_major = fman_get_revision_major(sc); + sc->sc_revision_minor = fman_get_revision_minor(sc); + + if (bootverbose) + device_printf(sc->sc_base.dev, "Hardware version: %d.%d.\n", + sc->sc_revision_major, sc->sc_revision_minor); + + fman_fill_soc_params(sc); + bus_set_region_4(sc->mem_res, FMAN_CGP_OFFSET, 0, sc->port_cgs / 4); + + if (fman_reset(sc) != 0) + goto err; + + if (fman_clear_iram(sc) != 0) + goto err; + + if (fman_dma_init(sc) != 0) + goto err; - *muramh = sc->muram_handle; + fman_fpm_init(sc); + + vmem_alloc(sc->muram_vmem, sc->total_fifo_size, M_BESTFIT | M_WAITOK, + &base_addr); + sc->bmi_fifo_base = base_addr; + + fman_bmi_init(sc); + fman_qmi_init(sc); + fman_hwp_init(sc); + if (fman_keygen_init(sc) != 0) + goto err; + + if (fman_enable(sc) != 0) + goto err; + + fman_enable_timestamp(sc); return (0); +err: + return (ENXIO); } -int -fman_get_bushandle(device_t dev, vm_offset_t *fm_base) +void +fman_get_revision(device_t dev, int *major, int *minor) { struct fman_softc *sc = device_get_softc(dev); - *fm_base = rman_get_bushandle(sc->mem_res); + if (major) + *major = sc->sc_revision_major; + if (minor) + *minor = sc->sc_revision_minor; +} + +/** @} */ + +static int +fman_init_muram(struct fman_softc *sc) +{ + u_long base, size; + phandle_t node; + + node = ofw_bus_get_node(sc->sc_base.dev); + for (node = OF_child(node); node != 0; node = OF_peer(node)) { + char compat[255]; + + if (OF_getprop(node, "compatible", compat, sizeof(compat)) < 0) + continue; + if (strcmp(compat, "fsl,fman-muram") == 0) + break; + } + if (node == 0) { + device_printf(sc->sc_base.dev, "no muram node\n"); + return (ENXIO); + } + if (fdt_regsize(node, &base, &size) != 0) { + device_printf(sc->sc_base.dev, "failed to get muram reg\n"); + return (ENXIO); + } + sc->muram_vmem = vmem_create("MURAM", + base, size, 1, 0, M_WAITOK); return (0); } @@ -413,20 +682,18 @@ int fman_attach(device_t dev) { struct fman_softc *sc; - struct fman_config cfg; pcell_t qchan_range[2]; + pcell_t cell; phandle_t node; sc = device_get_softc(dev); sc->sc_base.dev = dev; - /* Check if MallocSmart allocator is ready */ - if (XX_MallocSmartInit() != E_OK) { - device_printf(dev, "could not initialize smart allocator.\n"); - return (ENXIO); - } - + cell = 0; node = ofw_bus_get_node(dev); + OF_getencprop(node, "cell-index", &cell, sizeof(cell)); + sc->fm_id = cell; + if (OF_getencprop(node, "fsl,qman-channel-range", qchan_range, sizeof(qchan_range)) <= 0) { device_printf(dev, "Missing QMan channel range property!\n"); @@ -450,6 +717,12 @@ fman_attach(device_t dev) goto err; } + if (bus_setup_intr(dev, sc->irq_res, INTR_TYPE_NET | INTR_MPSAFE, + NULL, fman_intr, sc, &sc->irq_cookie) != 0) { + device_printf(dev, "error setting up interrupt handler.\n"); + goto err; + } + sc->err_irq_rid = 1; sc->err_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &sc->err_irq_rid, RF_ACTIVE | RF_SHAREABLE); @@ -458,20 +731,19 @@ fman_attach(device_t dev) goto err; } - /* Set FMan configuration */ - cfg.fman_device = dev; - cfg.fm_id = device_get_unit(dev); - cfg.mem_base_addr = rman_get_bushandle(sc->mem_res); - cfg.irq_num = (uintptr_t)sc->irq_res; - cfg.err_irq_num = (uintptr_t)sc->err_irq_res; - cfg.exception_callback = fman_exception_callback; - cfg.bus_error_callback = fman_error_callback; + /* Initialize the simplebus part of things */ + sc->rman.rm_type = RMAN_ARRAY; + sc->rman.rm_descr = "FMan range"; + rman_init_from_resource(&sc->rman, sc->mem_res); + simplebus_attach_impl(sc->sc_base.dev); + + if (fman_init_muram(sc) != 0) + goto err; + + /* TODO: Interrupts... */ - sc->fm_handle = fman_init(sc, &cfg); - if (sc->fm_handle == NULL) { - device_printf(dev, "could not be configured\n"); + if (fman_init(sc) != 0) goto err; - } bus_attach_children(dev); return (0); @@ -485,16 +757,14 @@ int fman_detach(device_t dev) { struct fman_softc *sc; + int rv; - sc = device_get_softc(dev); + rv = simplebus_detach(dev); - if (sc->muram_handle) { - FM_MURAM_Free(sc->muram_handle); - } + if (rv != 0) + return (rv); - if (sc->fm_handle) { - FM_Free(sc->fm_handle); - } + sc = device_get_softc(dev); if (sc->mem_res) { bus_release_resource(dev, SYS_RES_MEMORY, sc->mem_rid, @@ -511,6 +781,9 @@ fman_detach(device_t dev) sc->err_irq_res); } + if (sc->muram_vmem != NULL) + vmem_destroy(sc->muram_vmem); + return (0); } @@ -535,21 +808,152 @@ fman_shutdown(device_t dev) return (0); } +static void +fman_intr(void *arg) +{ + /* TODO: All FMAN interrupts */ +} + int fman_qman_channel_id(device_t dev, int port) { struct fman_softc *sc; - int qman_port_id[] = {0x31, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, - 0x2f, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}; int i; sc = device_get_softc(dev); - for (i = 0; i < sc->qman_chan_count; i++) { - if (qman_port_id[i] == port) - return (sc->qman_chan_base + i); + if (sc->sc_revision_major >= 6) { + static const int qman_port_id[] = { + 0x30, 0x31, 0x28, 0x29, 0x2a, 0x2b, + 0x2c, 0x2d, 0x02, 0x03, 0x04, 0x05, 0x07, 0x07 + }; + for (i = 0; i < sc->qman_chan_count; i++) { + if (qman_port_id[i] == port) + return (sc->qman_chan_base + i); + } + } else { + static const int qman_port_id[] = { + 0x31, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x01, + 0x02, 0x03, 0x04, 0x05, 0x07, 0x07 + }; + for (i = 0; i < sc->qman_chan_count; i++) { + if (qman_port_id[i] == port) + return (sc->qman_chan_base + i); + } } return (0); } +size_t +fman_get_bmi_max_fifo_size(device_t dev) +{ + struct fman_softc *sc = device_get_softc(dev); + + return (sc->bmi_max_fifo_size); +} + +int +fman_reset_mac(device_t dev, int mac_id) +{ + struct fman_softc *sc = device_get_softc(dev); + int timeout = 100; + uint32_t mask; + + if (mac_id < 0 || mac_id > 9) + return (EINVAL); + + /* MAC bits start at bit 1 for MAC0, and go down */ + mask = (1 << (30 - mac_id)); + bus_write_4(sc->mem_res, FM_RSTC, mask); + while ((bus_read_4(sc->mem_res, FM_RSTC) & mask) && --timeout) + DELAY(10); + + if (timeout == 0) + return (EIO); + + return (0); +} + +static int +fman_set_port_tasks(struct fman_softc *sc, int port_id, + uint8_t tasks, uint8_t extra) +{ + uint32_t reg; + + reg = bus_read_4(sc->mem_res, FMBM_PP(port_id)); + + reg &= ~(PP_MXT_M | PP_EXT_M); + reg |= ((uint32_t)(tasks - 1) << PP_MXT_S) | + ((uint32_t)extra << PP_EXT_S); + bus_write_4(sc->mem_res, FMBM_PP(port_id), reg); + + return (0); +} + +static int +fman_set_port_fifo_size(struct fman_softc *sc, int port_id, + uint32_t fifo_size, uint32_t extra) +{ + uint32_t reg; + + reg = (fifo_size / FMAN_BMI_FIFO_UNITS - 1) | + ((extra / FMAN_BMI_FIFO_UNITS) << PFS_EXBS_S); + + /* TODO: Make sure fifo size doesn't overrun */ + /* See Linux driver, fman set_size_of_fifo */ + + bus_write_4(sc->mem_res, FMBM_PFS(port_id), reg); + return (0); +} + +static int +fman_set_port_dmas(struct fman_softc *sc, int port_id, + int open_dmas, int extra_dmas) +{ + /* TODO: set port DMAs */ + return (0); +} + +static void +fman_set_port_liodn(struct fman_softc *sc, int port_id, uint32_t liodn) +{ + uint32_t reg; + + reg = bus_read_4(sc->mem_res, FMDM_PLRn(port_id)); + reg &= ~PLRN_LIODN_M(port_id); + reg |= liodn << PLRN_LIODN_S(port_id); + bus_write_4(sc->mem_res, FMDM_PLRn(port_id), reg); +} + +int +fman_set_port_params(device_t dev, struct fman_port_init_params *params) +{ + struct fman_softc *sc = device_get_softc(dev); + int error; + + error = fman_set_port_tasks(sc, params->port_id, + params->num_tasks, params->extra_tasks); + + if (error != 0) + return (error); + + if (!params->is_rx_port) { + } + error = fman_set_port_fifo_size(sc, params->port_id, params->fifo_size, + params->extra_fifo_size); + + if (error != 0) + return (error); + + error = fman_set_port_dmas(sc, params->port_id, + params->open_dmas, params->extra_dmas); + + if (error != 0) + return (error); + + fman_set_port_liodn(sc, params->port_id, params->liodn); + + return (0); +} + /** @} */ diff --git a/sys/dev/dpaa/fman.h b/sys/dev/dpaa/fman.h index a2ada5e16ffb..a0af1b36b5a3 100644 --- a/sys/dev/dpaa/fman.h +++ b/sys/dev/dpaa/fman.h @@ -28,6 +28,23 @@ #define FMAN_H_ #include <dev/fdt/simplebus.h> +#include <sys/vmem.h> + +#define FMAN_BMI_FIFO_UNITS 0x100 +#define FMAN_BMI_FIFO_ALIGN 0x100 + +#define FM_FD_ERR_DMA 0x01000000 +#define FM_FD_ERR_FPE 0x00080000 +#define FM_FD_ERR_FSE 0x00040000 +#define FM_FD_ERR_DIS 0x00020000 +#define FM_FD_ERR_EOF 0x00008000 +#define FM_FD_ERR_NSS 0x00004000 +#define FM_FD_ERR_KSO 0x00002000 +#define FM_FD_ERR_IPP 0x00000200 +#define FM_FD_ERR_PTE 0x00000080 +#define FM_FD_ERR_ISP 0x00000040 +#define FM_FD_ERR_PHE 0x00000020 +#define FM_FD_ERR_BLE 0x00000008 /** * FMan driver instance data. @@ -38,22 +55,91 @@ struct fman_softc { struct resource *irq_res; struct resource *err_irq_res; struct rman rman; + vmem_t *muram_vmem; int mem_rid; int irq_rid; int err_irq_rid; + void *irq_cookie; int qman_chan_base; int qman_chan_count; + int fm_id; + + int sc_revision_major; + int sc_revision_minor; + + uint16_t clock; + bool timestamps; + + uint32_t iram_size; + uint32_t dma_thresh_max_commq; + uint32_t dma_thresh_max_buf; + uint32_t dma_cam_num_entries; + uint32_t max_open_dmas; + + uint32_t qmi_max_tnums; + uint32_t qmi_def_tnums_thresh; + + uint32_t bmi_max_tasks; + uint32_t bmi_max_fifo_size; + uint32_t bmi_fifo_base; - t_Handle fm_handle; - t_Handle muram_handle; + uint32_t port_cgs; + uint32_t rx_ports; + uint32_t total_fifo_size; + + uint32_t qman_channel_base; + uint32_t qman_channels; +}; + +struct fman_port_init_params { + int port_id; + bool is_rx_port; + uint8_t num_tasks; + uint8_t extra_tasks; + uint8_t open_dmas; + uint8_t extra_dmas; + uint32_t fifo_size; + uint32_t extra_fifo_size; + uint8_t deq_pipeline_size; + uint16_t max_frame_length; + uint16_t liodn; }; +struct fman_parse_result { + uint8_t lpid; + uint8_t shimr; + uint16_t l2r; + uint16_t l3r; + uint8_t l4r; + uint8_t cpid; + uint16_t nxthdr; + uint16_t cksum; + uint32_t lcv; + uint8_t shim_off[2]; + uint8_t ip_pid_off; + uint8_t eth_off; + uint8_t llc_snap_off; + uint8_t vlan_tic_off[2]; + uint8_t last_e_type_off; + uint8_t pppoe_off; + uint8_t mpls_off[2]; + uint8_t ip_off[2]; + uint8_t gre_off; + uint8_t l4_off; + uint8_t nxthdr_off; +}; + +struct fman_internal_context { + struct fman_parse_result prs; + uint64_t timestamp; + uint64_t hash; +}; /** - * @group QMan bus interface. + * @group FMan bus interface. * @{ */ -struct resource * fman_alloc_resource(device_t bus, device_t child, int type, +struct resource *fman_alloc_resource(device_t bus, device_t child, int type, int rid, rman_res_t start, rman_res_t end, rman_res_t count, u_int flags); int fman_activate_resource(device_t bus, device_t child, struct resource *res); @@ -66,11 +152,16 @@ int fman_shutdown(device_t dev); int fman_read_ivar(device_t dev, device_t child, int index, uintptr_t *result); int fman_qman_channel_id(device_t, int); +void fman_get_revision(device_t, int *, int *); /** @} */ uint32_t fman_get_clock(struct fman_softc *sc); -int fman_get_handle(device_t dev, t_Handle *fmh); -int fman_get_muram_handle(device_t dev, t_Handle *muramh); int fman_get_bushandle(device_t dev, vm_offset_t *fm_base); +size_t fman_get_bmi_max_fifo_size(device_t); +int fman_reset_mac(device_t, int); +int fman_set_port_params(device_t dev, struct fman_port_init_params *params); +int fman_qman_channel_id(device_t, int); +int fman_set_mac_intr_handler(device_t, int, driver_intr_t, void *); +int fman_set_mac_err_handler(device_t, int, driver_intr_t, void *); #endif /* FMAN_H_ */ diff --git a/sys/dev/dpaa/fman_fdt.c b/sys/dev/dpaa/fman_fdt.c index 4d3723b6de4d..88f08269f086 100644 --- a/sys/dev/dpaa/fman_fdt.c +++ b/sys/dev/dpaa/fman_fdt.c @@ -34,10 +34,8 @@ #include <dev/ofw/ofw_bus.h> #include <dev/ofw/ofw_bus_subr.h> -#include <contrib/ncsw/inc/ncsw_ext.h> -#include <contrib/ncsw/inc/enet_ext.h> - #include "fman.h" +#include "fman_if.h" #define FFMAN_DEVSTR "Freescale Frame Manager" @@ -56,6 +54,12 @@ static device_method_t fman_methods[] = { DEVMETHOD(bus_alloc_resource, fman_alloc_resource), DEVMETHOD(bus_activate_resource, fman_activate_resource), DEVMETHOD(bus_release_resource, fman_release_resource), + + DEVMETHOD(fman_get_revision, fman_get_revision), + DEVMETHOD(fman_reset_mac, fman_reset_mac), + DEVMETHOD(fman_set_port_params, fman_set_port_params), + DEVMETHOD(fman_get_qman_channel_id, fman_qman_channel_id), + DEVMETHOD_END }; @@ -92,8 +96,8 @@ fman_get_clock(struct fman_softc *sc) if ((OF_getprop(node, "clock-frequency", &fman_clock, sizeof(fman_clock)) <= 0) || (fman_clock == 0)) { - device_printf(dev, "could not acquire correct frequency " - "from DTS\n"); + device_printf(dev, + "could not acquire correct frequency from DTS\n"); return (0); } diff --git a/sys/dev/dpaa/fman_if.m b/sys/dev/dpaa/fman_if.m new file mode 100644 index 000000000000..e7412ca64195 --- /dev/null +++ b/sys/dev/dpaa/fman_if.m @@ -0,0 +1,38 @@ +# +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2026 Justin Hibbits + +#include <machine/bus.h> +#include <dev/dpaa/fman.h> + +/** + * @brief DPAA FMan interface + * + */ +INTERFACE fman; + +METHOD void get_revision { + device_t dev; + int *major; + int *minor; +}; + +METHOD size_t get_bmi_max_fifo_size { + device_t dev; +}; + +METHOD int get_qman_channel_id { + device_t dev; + int port_id; +}; + +METHOD int reset_mac { + device_t dev; + int mac_id; +}; + +METHOD int set_port_params { + device_t dev; + struct fman_port_init_params *params; +}; diff --git a/sys/dev/dpaa/fman_mdio.c b/sys/dev/dpaa/fman_mdio.c index 8df716fc5571..d32b13ad0a79 100644 --- a/sys/dev/dpaa/fman_mdio.c +++ b/sys/dev/dpaa/fman_mdio.c @@ -46,17 +46,15 @@ #include <dev/ofw/ofw_bus.h> #include <dev/ofw/ofw_bus_subr.h> -#include <contrib/ncsw/inc/Peripherals/fm_ext.h> - #include "fman.h" #include "miibus_if.h" #define MDIO_LOCK() mtx_lock(&sc->sc_lock) #define MDIO_UNLOCK() mtx_unlock(&sc->sc_lock) -#define MDIO_WRITE4(sc,r,v) \ - bus_space_write_4(&bs_be_tag, sc->sc_handle, sc->sc_offset + r, v) +#define MDIO_WRITE4(sc, r, v) \ + bus_write_4(sc->sc_res, r, v) #define MDIO_READ4(sc, r) \ - bus_space_read_4(&bs_be_tag, sc->sc_handle, sc->sc_offset + r) + bus_read_4(sc->sc_res, r) #define MDIO_MIIMCFG 0x0 #define MDIO_MIIMCOM 0x4 @@ -76,8 +74,7 @@ static int pqmdio_miibus_writereg(device_t dev, int phy, int reg, int value); struct pqmdio_softc { struct mtx sc_lock; - bus_space_handle_t sc_handle; - int sc_offset; + struct resource *sc_res; }; static device_method_t pqmdio_methods[] = { @@ -123,13 +120,10 @@ static int pqmdio_fdt_attach(device_t dev) { struct pqmdio_softc *sc; - rman_res_t start, count; sc = device_get_softc(dev); - fman_get_bushandle(device_get_parent(dev), &sc->sc_handle); - bus_get_resource(dev, SYS_RES_MEMORY, 0, &start, &count); - sc->sc_offset = start; + sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 0, RF_ACTIVE); OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev); diff --git a/sys/dev/dpaa/fman_muram.c b/sys/dev/dpaa/fman_muram.c new file mode 100644 index 000000000000..a3df993dbb98 --- /dev/null +++ b/sys/dev/dpaa/fman_muram.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2026 Justin Hibbits + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/rman.h> +#include <sys/malloc.h> + +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> + +#include <machine/bus.h> + +#include "opt_platform.h" + +#include <powerpc/mpc85xx/mpc85xx.h> + +#include "fman.h" + +struct fman_muram_softc { + struct resource *sc_mem; + vmem_t sc_vmem; +}; + +static int +fman_muram_probe(device_t dev) +{ + if (!ofw_bus_is_compatible(dev, "fsl,fman-muram")) + return (ENXIO); + + device_set_desc(dev, "FMan MURAM"); + + return (BUS_PROBE_DEFAULT); +} + +static int +fman_muram_attach(device_t dev) +{ + struct fman_muram_softc *sc = device_get_softc(dev); + + sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 0, + RF_ACTIVE | RF_SHAREABLE); + + if (sc->sc_mem == NULL) { + device_printf(dev, "cannot allocate memory\n"); + return (ENXIO); + } + sc->sc_vmem = vmem_create("MURAM", rman_get_bushandle(sc->sc_mem), + rman_get_size(sc->sc_mem), +} + +static device_method_t muram_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, fman_muram_probe), + DEVMETHOD(device_attach, fman_muram_attach), + DEVMETHOD(device_detach, fman_muram_detach), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(fman_muram, fman_muram_driver, muram_methods, + sizeof(struct fman_muram_softc)); +EARLY_DRIVER_MODULE(fman_muram, fman, fman_muram_driver, 0, 0, + BUS_PASS_SUPPORTDEV); diff --git a/sys/dev/dpaa/fman_parser.h b/sys/dev/dpaa/fman_parser.h new file mode 100644 index 000000000000..aff95b1ae9d9 --- /dev/null +++ b/sys/dev/dpaa/fman_parser.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2026 Justin Hibbits + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef DPAA_FMAN_PARSER_H +#define DPAA_FMAN_PARSER_H + +#define FMAN_PARSE_RESULT_OFF 32 +#define L3R_FIRST_IPV4 0x8000 +#define L3R_FIRST_IPV6 0x4000 +#define L3R_FIRST_IP_M (L3R_FIRST_IPV4 | L3R_FIRST_IPV6) +#define L3R_LAST_IPV4 0x8000 +#define L3R_LAST_IPV6 0x4000 +#define L3R_LAST_IP_M (L3R_LAST_IPV4 | L3R_LAST_IPV6) +#define L3R_FIRST_ERROR 0x2000 +#define L3R_LAST_ERROR 0x0080 +#define L4R_TYPE_M 0xe0 +#define L4R_TYPE_TCP 0x20 +#define L4R_TYPE_UDP 0x40 +#define L4R_TYPE_IPSEC 0x60 +#define L4R_TYPE_SCTP 0x80 +#define L4R_DCCP 0xa0 +#define L4R_ERR 0x10 + +#endif diff --git a/sys/dev/dpaa/fman_port.c b/sys/dev/dpaa/fman_port.c new file mode 100644 index 000000000000..384d13a7b3a7 --- /dev/null +++ b/sys/dev/dpaa/fman_port.c @@ -0,0 +1,697 @@ +/* + * Copyright (c) 2026 Justin Hibbits + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/param.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <dev/ofw/ofw_bus_subr.h> +#include <machine/bus.h> +#include "fman.h" +#include "fman_parser.h" +#include "fman_port.h" +#include "fman_if.h" +#include "fman_port_if.h" + +struct fman_port_rsrc { + uint32_t num; + uint32_t extra; +}; + +#define MAX_BM_POOLS 64 +struct fman_port_softc { + device_t sc_dev; + struct resource *sc_mem; + int sc_port_id; + int sc_port_speed; + int sc_port_type; + + int sc_revision_major; + int sc_revision_minor; + + int sc_max_frame_length; + int sc_bm_max_pools; + int sc_max_port_fifo_size; + int sc_qman_channel_id; + + int sc_deq_byte_count; + int sc_deq_high_priority; + int sc_tx_deq_pipeline_depth; + + int sc_default_fqid; + int sc_err_fqid; + int pcd_base_fqid; + int pcd_fqs_count; + + int sc_max_ext_portals; + int sc_max_sub_portals; + + struct fman_port_rsrc sc_open_dmas; + struct fman_port_rsrc sc_tasks; + struct fman_port_rsrc sc_fifo_bufs; + + struct fman_port_buffer_pool sc_bpools[FMAN_PORT_MAX_POOLS]; +}; + +#define TX_10G_PORT_BASE 0x30 +#define RX_10G_PORT_BASE 0x10 + +#define FMAN_PORT_TYPE_TX 0 +#define FMAN_PORT_TYPE_RX 1 + +#define PORT_RX 0x01 +#define PORT_TX 0x02 +#define PORT_V3 0x04 + +#define FMBM_RCFG 0x000 +#define BMI_PORT_CFG_EN 0x80000000 +#define FMBM_RST 0x004 +#define FMBM_RDA 0x008 +#define RDA_WOPT 0x00100000 +#define FMBM_RFP 0x00c +#define FMBM_RFED 0x010 +#define BMI_RX_FRAME_END_CUT_SHIFT 16 +#define FMBM_RICP 0x014 /* Counts are units of 16 bytes */ +#define RICP_ICEOF_M 0x001f0000 +#define RICP_ICEOF_S 16 +#define RICP_ICIOF_M 0x00000f00 +#define RICP_ICIOF_S 8 +#define RICP_ICSZ_S 0x0000001f +#define FMBM_RIM 0x018 +#define FMBM_REBM 0x01c +#define REBM_BSM_M 0x01ff0000 +#define REBM_BSM_S 16 +#define REBM_BEM_M 0x000001ff +#define FMBM_RFNE 0x020 +#define FMBM_RFCA 0x024 +#define RFCA_OR 0x80000000 +#define RFCA_COLOR 0x0c000000 +#define RFCA_SYNC 0x03000000 +#define RFCA_SYNC_REQ 0x02000000 +#define RFCA_MR 0x003f0000 +#define RFCA_MR_DEF 0x003c0000 +#define FMBM_RFPNE 0x028 +#define FMBM_RETH 0x038 +#define RETH_ETHE 0x80000000 /* Excessive Threshold Enable */ +#define FMBM_RFQID 0x060 +#define FMBM_REFQID 0x064 +#define FMBM_RFSDM 0x068 +#define FMBM_RFSEM 0x06c +#define FMBM_RFENE 0x070 +#define FMBM_REBMPI(i) (0x100 + (4 * (i))) +#define REBMPI_VAL 0x80000000 +#define REBMPI_ACE 0x40000000 +#define REBMPI_BPID_S 16 +#define FMBM_RSTC 0x0200 +#define RSTC_EN 0x80000000 + +#define FMBM_TCFG 0x000 +#define FMBM_TST 0x004 +#define FMBM_TDA 0x008 +#define FMBM_TFP 0x00c +#define BMI_FIFO_PIPELINE_DEPTH_SHIFT 12 +#define FMBM_TFED 0x010 +#define FMBM_TICP 0x014 +#define TICP_ICEOF_M 0x001f0000 +#define TICP_ICEOF_S 16 +#define TICP_ICIOF_M 0x00000f00 +#define TICP_ICIOF_S 8 +#define TICP_ICSZ_S 0x0000001f +#define FMBM_TFDNE 0x018 +#define FMBM_TFCA 0x01c +#define TFCA_MR_DEF 0 +#define TFCA_ATTR_ORDER 0x80000000 +#define FMBM_TCFQID 0x020 +#define FMBM_TEFQID 0x024 +#define FMBM_TFENE 0x028 +#define FMBM_TFNE 0x070 +#define TFNE_EBD 0x80000000 + +#define FMQM_PNC 0x400 +#define PNC_EN 0x80000000 +#define PNC_STEN 0x80000000 +#define FMQM_PNS 0x404 +#define PNS_DEQ_FD_BSY 0x20000000 +#define FMQM_PNEN 0x41c +#define FMQM_PNDN 0x42c +#define FMQM_PNDC 0x430 +#define QMI_DEQ_CFG_PRI 0x80000000 +#define QMI_DEQ_CFG_TYPE1 0x10000000 +#define QMI_DEQ_CFG_TYPE2 0x20000000 +#define QMI_DEQ_CFG_TYPE3 0x30000000 +#define QMI_DEQ_CFG_PREFETCH_PARTIAL 0x01000000 +#define QMI_DEQ_CFG_PREFETCH_FULL 0x03000000 +#define QMI_DEQ_CFG_SP_MASK 0xf +#define QMI_DEQ_CFG_SP_SHIFT 20 + +#define HWP_PCAC 0xbf8 +#define HWP_PCAC_PSTOP 0x00000001 +#define HWP_HXS_PCAC_PSTAT 0x00000100 +#define HWP_HXS_SSA(x) (0x800 + x * 2 * sizeof(uint32_t)) +#define HWP_HXS_LCV(x) (0x800 + (x * 2 + 1) * sizeof(uint32_t)) +#define HWP_HXS_TCP 0xA +#define HWP_HXS_UDP 0xB +#define HXS_SH_PAD_REM 0x80000000 +#define HWP_HXS_COUNT 16 + +#define PORT_MAX_FRAME_LENGTH 9600 + +#define NIA_ORDER_RESTORE 0x00800000 +#define NIA_ENG_BMI 0x00500000 +#define NIA_ENG_QMI_DEQ 0x00580000 +#define NIA_ENG_QMI_ENQ 0x00540000 +#define NIA_ENG_HWP 0x00440000 +#define NIA_ENG_HWK 0x00480000 +#define NIA_BMI_AC_TX_RELEASE 0x000002c0 +#define NIA_BMI_AC_TX 0x00000274 +#define NIA_BMI_AC_RELEASE 0x000000c0 +#define NIA_BMI_AC_ENQ_FRAME 0x00000002 +#define NIA_BMI_AC_FETCH_ALLFRAME 0x0000020c + +#define BMI_RX_ERR (FM_FD_ERR_DMA | FM_FD_ERR_FPE | \ + FM_FD_ERR_FSE | FM_FD_ERR_DIS | \ + FM_FD_ERR_EOF | FM_FD_ERR_NSS | \ + FM_FD_ERR_KSO | FM_FD_ERR_IPP | \ + FM_FD_ERR_PTE | FM_FD_ERR_PHE | \ + FM_FD_ERR_BLE) + +/* Default configurations */ +#define DEFAULT_RX_CUT_END_BYTES 4 + +static struct ofw_compat_data compats[] = { + { "fsl,fman-v2-port-rx", PORT_RX }, + { "fsl,fman-v2-port-tx", PORT_TX }, + { "fsl,fman-v3-port-rx", PORT_V3 | PORT_RX }, + { "fsl,fman-v3-port-tx", PORT_V3 | PORT_TX }, + { NULL, 0 } +}; + +static int +fman_port_probe(device_t dev) +{ + if (ofw_bus_search_compatible(dev, compats)->ocd_str == NULL) + return (ENXIO); + + device_set_desc(dev, "FMan port"); + + return (BUS_PROBE_DEFAULT); +} + +static int +fman_port_attach(device_t dev) +{ + struct fman_port_softc *sc; + phandle_t node; + pcell_t cell; + uintptr_t compat_data = + ofw_bus_search_compatible(dev, compats)->ocd_data; + int port_speed = 1000; + int port_type; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + + node = ofw_bus_get_node(dev); + if (OF_getencprop(node, "cell-index", &cell, sizeof(cell)) < 0) { + device_printf(dev, "No cell-index property"); + return (ENXIO); + } + + sc->sc_port_id = cell; + + sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 0, + RF_ACTIVE | RF_SHAREABLE); + + if (sc->sc_mem == NULL) { + device_printf(dev, "failed to allocate MMIO"); + return (ENXIO); + } + + FMAN_GET_REVISION(device_get_parent(dev), + &sc->sc_revision_major, &sc->sc_revision_minor); + + if ((compat_data & PORT_TX) == PORT_TX) + port_type = FMAN_PORT_TYPE_TX; + else + port_type = FMAN_PORT_TYPE_RX; + + if ((compat_data & PORT_V3) == PORT_V3) { + if (OF_hasprop(node, "fsl,fman-10g-port")) + port_speed = 10000; + } else { + if ((compat_data & PORT_TX) && + sc->sc_port_id > TX_10G_PORT_BASE) + port_speed = 10000; + else if ((compat_data & PORT_RX) && + sc->sc_port_id > RX_10G_PORT_BASE) + port_speed = 10000; + } + + if (sc->sc_port_speed == 10000) { + sc->sc_deq_high_priority = true; + sc->sc_deq_byte_count = 0x1400; + } else { + sc->sc_deq_high_priority = false; + sc->sc_deq_byte_count = 0x0400; + } + + sc->sc_port_type = port_type; + sc->sc_port_speed = port_speed; + + sc->sc_bm_max_pools = MAX_BM_POOLS; + sc->sc_max_frame_length = PORT_MAX_FRAME_LENGTH; + + if (port_type == FMAN_PORT_TYPE_TX) + sc->sc_qman_channel_id = + FMAN_GET_QMAN_CHANNEL_ID(device_get_parent(dev), + sc->sc_port_id); + + OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev); + + return (0); +} + +static int +fman_port_detach(device_t dev) +{ + struct fman_port_softc *sc = device_get_softc(dev); + + if (sc->sc_mem != NULL) + bus_release_resource(dev, sc->sc_mem); + + return (0); +} + +static int +fman_port_config(device_t dev, struct fman_port_params *params) +{ + struct fman_port_softc *sc = device_get_softc(dev); + + sc->sc_default_fqid = params->dflt_fqid; + sc->sc_err_fqid = params->err_fqid; + + sc->sc_max_port_fifo_size = + FMAN_GET_BMI_MAX_FIFO_SIZE(device_get_parent(dev)); + switch (sc->sc_revision_major) { + case 2: + case 3: + sc->sc_max_ext_portals = 4; + sc->sc_max_sub_portals = 12; + break; + case 6: + sc->sc_max_ext_portals = 8; + sc->sc_max_sub_portals = 16; + break; + } + if (sc->sc_revision_major >= 6 && + sc->sc_port_type == FMAN_PORT_TYPE_TX && sc->sc_port_speed == 1000) + /* Errata A005127 workaround */ + bus_write_4(sc->sc_mem, FMBM_TFP, 0x00001013); + + sc->sc_tasks.extra = 0; + + switch (sc->sc_port_speed) { + case 10000: + if (sc->sc_revision_major < 6) { + sc->sc_tasks.num = 16; + if (sc->sc_port_type == FMAN_PORT_TYPE_RX) + sc->sc_tasks.extra = 8; + } else + sc->sc_tasks.num = 14; + break; + case 1000: + if (sc->sc_revision_major >= 6) + sc->sc_tasks.num = 4; + else { + sc->sc_tasks.num = 3; + if (sc->sc_port_type == FMAN_PORT_TYPE_RX) + sc->sc_tasks.extra = 2; + } + break; + default: + sc->sc_tasks.num = 0; + break; + } + + /* Open DMAs */ + if (sc->sc_revision_major >= 6) { + sc->sc_open_dmas.extra = 0; + if (sc->sc_port_speed == 10000) { + if (sc->sc_port_type == FMAN_PORT_TYPE_TX) + sc->sc_open_dmas.num = 12; + else + sc->sc_open_dmas.num = 8; + } else { + if (sc->sc_port_type == FMAN_PORT_TYPE_TX) + sc->sc_open_dmas.num = 3; + else + sc->sc_open_dmas.num = 2; + } + } else { + if (sc->sc_port_speed == 10000) { + sc->sc_open_dmas.num = 8; + sc->sc_open_dmas.num = 8; + } else { + sc->sc_open_dmas.num = 1; + sc->sc_open_dmas.extra = 1; + } + } + + /* FIFO bufs */ + if (sc->sc_revision_major >= 6) { + if (sc->sc_port_type == FMAN_PORT_TYPE_TX) + if (sc->sc_port_speed == 10000) + sc->sc_fifo_bufs.num = 64; + else + sc->sc_fifo_bufs.num = 50; + else + if (sc->sc_port_speed == 10000) + sc->sc_fifo_bufs.num = 96; + else + sc->sc_fifo_bufs.num = 50; + } else { + if (sc->sc_port_type == FMAN_PORT_TYPE_TX) + if (sc->sc_port_speed == 10000) + sc->sc_fifo_bufs.num = 48; + else + sc->sc_fifo_bufs.num = 44; + else + if (sc->sc_port_speed == 10000) + sc->sc_fifo_bufs.num = 48; + else + sc->sc_fifo_bufs.num = 45; + } + + sc->sc_fifo_bufs.extra = 0; + sc->sc_fifo_bufs.num *= FMAN_BMI_FIFO_UNITS; + + if (sc->sc_port_type == FMAN_PORT_TYPE_RX) + for (int i = 0; i < params->rx_params.num_pools; i++) + sc->sc_bpools[i] = params->rx_params.bpools[i]; + + /* TODO: buf_margins? See fman_sp_build_buffer_struct */ + + return (0); +} + +static int +fman_port_init_bmi_rx(struct fman_port_softc *sc) +{ + uint32_t reg; + + /* TODO: Sort the buffer pool list. */ + /* TODO: Backup pools */ + /* TODO: Depletion mode */ + for (int i = 0; i < FMAN_PORT_MAX_POOLS; i++) { + /* Initialize the external pool info */ + if (sc->sc_bpools[i].size != 0) { + bus_write_4(sc->sc_mem, FMBM_REBMPI(i), + REBMPI_VAL | REBMPI_ACE | + (sc->sc_bpools[i].bpid << REBMPI_BPID_S) | + sc->sc_bpools[i].size); + } else + /* Mark invalid if zero */ + bus_write_4(sc->sc_mem, FMBM_REBMPI(i), 0); + } + + bus_write_4(sc->sc_mem, FMBM_RDA, RDA_WOPT); + + bus_write_4(sc->sc_mem, FMBM_RFCA, + RFCA_OR | RFCA_SYNC_REQ | RFCA_MR_DEF); + + bus_write_4(sc->sc_mem, FMBM_RFPNE, + NIA_ENG_BMI | NIA_BMI_AC_ENQ_FRAME); + bus_write_4(sc->sc_mem, FMBM_RFENE, + NIA_ENG_QMI_ENQ | NIA_ORDER_RESTORE); + + bus_write_4(sc->sc_mem, FMBM_RFQID, sc->sc_default_fqid); + bus_write_4(sc->sc_mem, FMBM_REFQID, sc->sc_err_fqid); + + if (sc->sc_revision_major < 6) + bus_write_4(sc->sc_mem, FMBM_RETH, RETH_ETHE); + + /* Errata A006320 makes CFED field bad */ + if (sc->sc_revision_major == 6 && (sc->sc_revision_minor == 0)) + /* These are under errata A006320 */; + else + bus_write_4(sc->sc_mem, FMBM_RFED, + DEFAULT_RX_CUT_END_BYTES << BMI_RX_FRAME_END_CUT_SHIFT); + + /* Insert internal context ahead of the frame */ + reg = sizeof(struct fman_internal_context) << REBM_BSM_S; + bus_write_4(sc->sc_mem, FMBM_REBM, reg); + reg = howmany(FMAN_PARSE_RESULT_OFF, 0x10) << RICP_ICIOF_S; + reg |= howmany(sizeof(struct fman_internal_context), 0x10); + bus_write_4(sc->sc_mem, FMBM_RICP, reg); + + bus_write_4(sc->sc_mem, FMBM_RFNE, NIA_ENG_HWP); + bus_write_4(sc->sc_mem, FMBM_RFSDM, FM_FD_ERR_DIS); + bus_write_4(sc->sc_mem, FMBM_RFSEM, BMI_RX_ERR & ~FM_FD_ERR_DIS); + + return (0); +} + +static int +fman_port_init_bmi_tx(struct fman_port_softc *sc) +{ + uint32_t reg; + int depth; + + bus_write_4(sc->sc_mem, FMBM_TCFG, 0); + bus_write_4(sc->sc_mem, FMBM_TDA, 0); + bus_write_4(sc->sc_mem, FMBM_TFED, 0); + if (sc->sc_port_speed == 10000) + depth = 4; + else if (sc->sc_revision_major >= 6) + depth = 2; + else + depth = 1; + sc->sc_tx_deq_pipeline_depth = depth; + reg = ((depth - 1) << BMI_FIFO_PIPELINE_DEPTH_SHIFT) | 0x13; + bus_write_4(sc->sc_mem, FMBM_TFP, reg); + + /* Default color: green */ + bus_write_4(sc->sc_mem, FMBM_TFCA, + TFCA_MR_DEF | TFCA_ATTR_ORDER); + + bus_write_4(sc->sc_mem, FMBM_TFDNE, NIA_ENG_QMI_DEQ); + bus_write_4(sc->sc_mem, FMBM_TFENE, + NIA_ENG_QMI_ENQ | NIA_ORDER_RESTORE); + + /* Insert internal context ahead of the frame */ + reg = howmany(FMAN_PARSE_RESULT_OFF, 0x10) << TICP_ICIOF_S; + reg |= howmany(sizeof(struct fman_internal_context), 0x10); + bus_write_4(sc->sc_mem, FMBM_TICP, reg); + + if (sc->sc_revision_major >= 6) + bus_write_4(sc->sc_mem, FMBM_TFNE, + (sc->sc_default_fqid == 0 ? TFNE_EBD : 0) | + NIA_BMI_AC_FETCH_ALLFRAME); + bus_write_4(sc->sc_mem, FMBM_TCFQID, sc->sc_default_fqid); + bus_write_4(sc->sc_mem, FMBM_TEFQID, sc->sc_err_fqid); + + return (0); +} + +static int +fman_port_init_hwp(struct fman_port_softc *sc) +{ + int i; + + /* Stop the parser so we can initialize it for our uses */ + bus_write_4(sc->sc_mem, HWP_PCAC, HWP_PCAC_PSTOP); + + for (i = 0; i < 100 && + (bus_read_4(sc->sc_mem, HWP_PCAC) & HWP_HXS_PCAC_PSTAT) != 0; i++) { + DELAY(10); + } + if (i == 100) { + device_printf(sc->sc_dev, "Timeout stopping HW parser\n"); + return (ENXIO); + } + + /* set the parser examination config */ + for (i = 0; i < HWP_HXS_COUNT; i++) { + bus_write_4(sc->sc_mem, HWP_HXS_SSA(i), 0); + bus_write_4(sc->sc_mem, HWP_HXS_LCV(i), 0xffffffff); + } + bus_write_4(sc->sc_mem, HWP_HXS_SSA(HWP_HXS_TCP), HXS_SH_PAD_REM); + bus_write_4(sc->sc_mem, HWP_HXS_SSA(HWP_HXS_UDP), HXS_SH_PAD_REM); + + /* Re-enable the parser */ + bus_write_4(sc->sc_mem, HWP_PCAC, 0); + + return (0); +} + +static int +fman_port_init_qmi(struct fman_port_softc *sc) +{ + uint32_t reg; + + if (sc->sc_port_type == FMAN_PORT_TYPE_RX) { + bus_write_4(sc->sc_mem, FMQM_PNEN, + NIA_ENG_BMI | NIA_BMI_AC_RELEASE); + return (0); + } + + /* TX port */ + bus_write_4(sc->sc_mem, FMQM_PNDN, + NIA_ENG_BMI | NIA_BMI_AC_TX); + /* TX port */ + bus_write_4(sc->sc_mem, FMQM_PNEN, + NIA_ENG_BMI | NIA_BMI_AC_TX_RELEASE); + + reg = 0; + + if (sc->sc_deq_high_priority) + reg |= QMI_DEQ_CFG_PRI; + + reg |= QMI_DEQ_CFG_TYPE1; + reg |= QMI_DEQ_CFG_PREFETCH_FULL; + reg |= (sc->sc_qman_channel_id & QMI_DEQ_CFG_SP_MASK) << QMI_DEQ_CFG_SP_SHIFT; + reg |= sc->sc_deq_byte_count; + bus_write_4(sc->sc_mem, FMQM_PNDC, reg); + + return (0); +} + +static int +fman_port_init(device_t dev) +{ + struct fman_port_init_params params; + struct fman_port_softc *sc = device_get_softc(dev); + int err; + + if (sc->sc_port_type == FMAN_PORT_TYPE_RX) { + /* Set up RX buffers and fifo */ + } + params.port_id = sc->sc_port_id; + params.is_rx_port = (sc->sc_port_type == FMAN_PORT_TYPE_RX); + params.num_tasks = sc->sc_tasks.num; + params.extra_tasks = sc->sc_tasks.extra; + params.open_dmas = sc->sc_open_dmas.num; + params.extra_dmas = sc->sc_open_dmas.extra; + params.fifo_size = sc->sc_fifo_bufs.num; + params.extra_fifo_size = sc->sc_fifo_bufs.extra; + params.max_frame_length = sc->sc_max_frame_length; + params.deq_pipeline_size = sc->sc_tx_deq_pipeline_depth; + + /* TODO: verify_size_of_fifo() from Linux driver */ + err = FMAN_SET_PORT_PARAMS(device_get_parent(dev), ¶ms); + + if (err != 0) + return (err); + + if (sc->sc_port_type == FMAN_PORT_TYPE_TX) + err = fman_port_init_bmi_tx(sc); + else { + err = fman_port_init_bmi_rx(sc); + if (err == 0) + fman_port_init_hwp(sc); + } + + if (err != 0) + return (err); + + err = fman_port_init_qmi(sc); + + /* TODO: keygen here */ + + return (err); +} + +static int +fman_port_disable(device_t dev) +{ + struct fman_port_softc *sc; + uint32_t reg; + int count; + + sc = device_get_softc(dev); + + switch (sc->sc_port_type) { + case FMAN_PORT_TYPE_TX: + reg = bus_read_4(sc->sc_mem, FMQM_PNC); + bus_write_4(sc->sc_mem, FMQM_PNC, reg & ~PNC_EN); + for (count = 0; count < 100; count++) { + DELAY(10); + reg = bus_read_4(sc->sc_mem, FMQM_PNS); + if (!(reg & PNS_DEQ_FD_BSY)) + break; + } + if (count == 100) + device_printf(sc->sc_dev, "Timeout stopping QMI\n"); + reg = bus_read_4(sc->sc_mem, FMBM_TCFG); + bus_write_4(sc->sc_mem, FMBM_TCFG, reg & ~BMI_PORT_CFG_EN); + for (count = 0; count < 100; count++) { + DELAY(10); + reg = bus_read_4(sc->sc_mem, FMBM_TST); + if (!(reg & PNS_DEQ_FD_BSY)) + break; + } + if (count == 100) + device_printf(sc->sc_dev, "Timeout stopping BMI"); + break; + case FMAN_PORT_TYPE_RX: + reg = bus_read_4(sc->sc_mem, FMBM_RCFG); + bus_write_4(sc->sc_mem, FMBM_RCFG, reg & ~BMI_PORT_CFG_EN); + for (count = 0; count < 100; count++) { + DELAY(10); + reg = bus_read_4(sc->sc_mem, FMBM_RST); + if (!(reg & PNS_DEQ_FD_BSY)) + break; + } + if (count == 100) + device_printf(sc->sc_dev, "Timeout stopping BMI"); + break; + } + + return (0); +} + +static int +fman_port_enable(device_t dev) +{ + struct fman_port_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + switch (sc->sc_port_type) { + case FMAN_PORT_TYPE_TX: + reg = bus_read_4(sc->sc_mem, FMQM_PNC); + bus_write_4(sc->sc_mem, FMQM_PNC, reg | PNC_EN | PNC_STEN); + reg = bus_read_4(sc->sc_mem, FMBM_TCFG); + bus_write_4(sc->sc_mem, FMBM_TCFG, reg | BMI_PORT_CFG_EN); + break; + case FMAN_PORT_TYPE_RX: + reg = bus_read_4(sc->sc_mem, FMBM_RCFG); + bus_write_4(sc->sc_mem, FMQM_PNC, reg | PNC_EN | PNC_STEN); + bus_write_4(sc->sc_mem, FMBM_RCFG, reg | BMI_PORT_CFG_EN); + bus_write_4(sc->sc_mem, FMBM_RSTC, RSTC_EN); + break; + } + + return (0); +} + +static device_method_t fman_port_methods[] = { + DEVMETHOD(device_probe, fman_port_probe), + DEVMETHOD(device_attach, fman_port_attach), + DEVMETHOD(device_detach, fman_port_detach), + + DEVMETHOD(fman_port_config, fman_port_config), + DEVMETHOD(fman_port_init, fman_port_init), + DEVMETHOD(fman_port_enable, fman_port_enable), + DEVMETHOD(fman_port_disable, fman_port_disable), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(fman_port, fman_port_driver, fman_port_methods, + sizeof(struct fman_port_softc)); +EARLY_DRIVER_MODULE(fman_port, fman, fman_port_driver, 0, 0, + BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE); diff --git a/sys/dev/dpaa/fman_port.h b/sys/dev/dpaa/fman_port.h new file mode 100644 index 000000000000..8803c5e5f7c9 --- /dev/null +++ b/sys/dev/dpaa/fman_port.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2026 Justin Hibbits + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef DPAA_FMAN_PORT_H +#define DPAA_FMAN_PORT_H + +#define FMAN_PORT_MAX_POOLS 4 +struct fman_port_buffer_pool { + uint8_t bpid; + uint16_t size; +}; + +struct fman_port_params { + uint32_t dflt_fqid; /* Must not be 0 */ + uint32_t err_fqid; + union { + struct { + int num_pools; + struct fman_port_buffer_pool bpools[FMAN_PORT_MAX_POOLS]; + } rx_params; + struct { + } tx_params; + }; +}; + +#endif diff --git a/sys/dev/dpaa/fman_port_if.m b/sys/dev/dpaa/fman_port_if.m new file mode 100644 index 000000000000..fe6159340c2c --- /dev/null +++ b/sys/dev/dpaa/fman_port_if.m @@ -0,0 +1,33 @@ +# +# Copyright (c) 2026 Justin Hibbits +# +# SPDX-License-Identifier: BSD-2-Clause + +#include <machine/bus.h> +#include <dev/dpaa/fman_port.h> + +/** + * @brief DPAA FMan Port interface + * + */ +INTERFACE fman_port; + +/** + * @brief Configure the port for a specific purpose + */ +METHOD int config { + device_t dev; + struct fman_port_params *params; +}; + +METHOD int init { + device_t dev; +}; + +METHOD int disable { + device_t dev; +}; + +METHOD int enable { + device_t dev; +}; diff --git a/sys/dev/dpaa/fman_xmdio.c b/sys/dev/dpaa/fman_xmdio.c new file mode 100644 index 000000000000..521c30860dc5 --- /dev/null +++ b/sys/dev/dpaa/fman_xmdio.c @@ -0,0 +1,284 @@ +/* + * Copyright (c) 2026 Justin Hibbits + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/bus.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/resource.h> +#include <sys/socket.h> + +#include <machine/bus.h> + +#include <net/if.h> +#include <net/if_media.h> +#include <net/if_types.h> +#include <net/if_var.h> + +#include <dev/mdio/mdio.h> +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> + +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> + +#include "fman.h" +#include "miibus_if.h" +#include "mdio_if.h" + +#define MDIO_LOCK() mtx_lock(&sc->sc_lock) +#define MDIO_UNLOCK() mtx_unlock(&sc->sc_lock) +#define MDIO_WRITE4(sc, r, v) \ + bus_write_4(sc->sc_res, r, v) +#define MDIO_READ4(sc, r) \ + bus_read_4(sc->sc_res, r) + +#define MDIO_CFG 0x30 +#define CFG_ENC45 0x00000040 +#define MDIO_STAT 0x30 +#define STAT_BUSY 0x80000000 +#define STAT_MDIO_RD_ER 0x00000002 +#define MDIO_CTL 0x34 +#define CTL_READ 0x00008000 +#define MDIO_DATA 0x38 +#define MDIO_ADDR 0x3c + +static int xmdio_fdt_probe(device_t dev); +static int xmdio_fdt_attach(device_t dev); +static int xmdio_detach(device_t dev); +static int xmdio_miibus_readreg(device_t dev, int phy, int reg); +static int xmdio_miibus_writereg(device_t dev, int phy, int reg, int value); +static int xmdio_mdio_readextreg(device_t dev, int phy, int devad, int reg); +static int xmdio_mdio_writeextreg(device_t dev, int phy, int devad, int reg, + int val); + +struct xmdio_softc { + struct mtx sc_lock; + struct resource *sc_res; +}; + +static struct ofw_compat_data mdio_compat_data[] = { + {"fsl,fman-memac-mdio", 0}, + {"fsl,fman-xmdio", 0}, + {NULL, 0} +}; + +static device_method_t xmdio_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, xmdio_fdt_probe), + DEVMETHOD(device_attach, xmdio_fdt_attach), + DEVMETHOD(device_detach, xmdio_detach), + DEVMETHOD(bus_add_child, bus_generic_add_child), + + /* MII interface */ + DEVMETHOD(miibus_readreg, xmdio_miibus_readreg), + DEVMETHOD(miibus_writereg, xmdio_miibus_writereg), + + /* MDIO interface */ + DEVMETHOD(mdio_readreg, xmdio_miibus_readreg), + DEVMETHOD(mdio_writereg, xmdio_miibus_writereg), + DEVMETHOD(mdio_readextreg, xmdio_mdio_readextreg), + DEVMETHOD(mdio_writeextreg, xmdio_mdio_writeextreg), + + DEVMETHOD_END +}; + +static driver_t xmdio_driver = { + "xmdio", + xmdio_methods, + sizeof(struct xmdio_softc), +}; + +EARLY_DRIVER_MODULE(xmdio, fman, xmdio_driver, 0, 0, + BUS_PASS_SUPPORTDEV); +DRIVER_MODULE(miibus, xmdio, miibus_driver, 0, 0); +DRIVER_MODULE(mdio, xmdio, mdio_driver, 0, 0); +MODULE_DEPEND(xmdio, miibus, 1, 1, 1); + +static int +xmdio_fdt_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_search_compatible(dev, mdio_compat_data)->ocd_str) + return (ENXIO); + + device_set_desc(dev, "Freescale XGMAC MDIO"); + + return (BUS_PROBE_DEFAULT); +} + +static int +xmdio_fdt_attach(device_t dev) +{ + struct xmdio_softc *sc; + + sc = device_get_softc(dev); + + sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 0, RF_ACTIVE); + + OF_device_register_xref(OF_xref_from_node(ofw_bus_get_node(dev)), dev); + + mtx_init(&sc->sc_lock, device_get_nameunit(dev), "XMDIO lock", + MTX_DEF); + + return (0); +} + +static int +xmdio_detach(device_t dev) +{ + struct xmdio_softc *sc; + + sc = device_get_softc(dev); + + mtx_destroy(&sc->sc_lock); + + return (0); +} + +static void +set_clause45(struct xmdio_softc *sc) +{ + uint32_t reg; + + reg = MDIO_READ4(sc, MDIO_CFG); + MDIO_WRITE4(sc, MDIO_CFG, reg | CFG_ENC45); +} + +static void +set_clause22(struct xmdio_softc *sc) +{ + uint32_t reg; + + reg = MDIO_READ4(sc, MDIO_CFG); + MDIO_WRITE4(sc, MDIO_CFG, reg & ~CFG_ENC45); +} + +static int +xmdio_wait_no_busy(struct xmdio_softc *sc) +{ + uint32_t count, val; + + for (count = 1000; count > 0; count--) { + val = MDIO_READ4(sc, MDIO_CFG); + if ((val & STAT_BUSY) == 0) + break; + DELAY(1); + } + + if (count == 0) + return (0xffff); + + return (0); +} + +int +xmdio_miibus_readreg(device_t dev, int phy, int reg) +{ + struct xmdio_softc *sc; + int rv; + uint32_t ctl; + + sc = device_get_softc(dev); + + MDIO_LOCK(); + + set_clause22(sc); + ctl = (phy << 5) | reg; + MDIO_WRITE4(sc, MDIO_CTL, ctl | CTL_READ); + + MDIO_READ4(sc, MDIO_CTL); + + if (xmdio_wait_no_busy(sc)) + rv = 0xffff; + else + rv = MDIO_READ4(sc, MDIO_DATA); + + MDIO_WRITE4(sc, MDIO_CTL, 0); + MDIO_UNLOCK(); + + return (rv); +} + +int +xmdio_miibus_writereg(device_t dev, int phy, int reg, int value) +{ + struct xmdio_softc *sc; + + sc = device_get_softc(dev); + + MDIO_LOCK(); + set_clause22(sc); + /* Stop the MII management read cycle */ + MDIO_WRITE4(sc, MDIO_CTL, (phy << 5) | reg); + + MDIO_WRITE4(sc, MDIO_DATA, value); + + /* Wait till MII management write is complete */ + xmdio_wait_no_busy(sc); + MDIO_UNLOCK(); + + return (0); +} + +static int +xmdio_mdio_readextreg(device_t dev, int phy, int devad, int reg) +{ + struct xmdio_softc *sc; + int rv; + uint32_t ctl; + + sc = device_get_softc(dev); + + MDIO_LOCK(); + + set_clause45(sc); + ctl = (phy << 5) | devad; + MDIO_WRITE4(sc, MDIO_CTL, ctl); + MDIO_WRITE4(sc, MDIO_ADDR, reg); + xmdio_wait_no_busy(sc); + MDIO_WRITE4(sc, MDIO_CTL, ctl | CTL_READ); + MDIO_READ4(sc, MDIO_CTL); + + xmdio_wait_no_busy(sc); + + if (MDIO_READ4(sc, MDIO_STAT) & STAT_MDIO_RD_ER) + rv = 0xffff; + else + rv = MDIO_READ4(sc, MDIO_DATA); + + MDIO_WRITE4(sc, MDIO_CTL, 0); + MDIO_UNLOCK(); + + return (rv); +} + +static int +xmdio_mdio_writeextreg(device_t dev, int phy, int devad, int reg, int val) +{ + struct xmdio_softc *sc; + + sc = device_get_softc(dev); + + MDIO_LOCK(); + set_clause45(sc); + /* Stop the MII management read cycle */ + MDIO_WRITE4(sc, MDIO_CTL, (phy << 5) | devad); + + MDIO_WRITE4(sc, MDIO_DATA, val); + + /* Wait till MII management write is complete */ + xmdio_wait_no_busy(sc); + MDIO_UNLOCK(); + + return (0); +} + diff --git a/sys/dev/dpaa/if_dtsec.c b/sys/dev/dpaa/if_dtsec.c index a5f9955061a4..0d886abc5345 100644 --- a/sys/dev/dpaa/if_dtsec.c +++ b/sys/dev/dpaa/if_dtsec.c @@ -54,184 +54,54 @@ #include "miibus_if.h" -#include <contrib/ncsw/inc/integrations/dpaa_integration_ext.h> -#include <contrib/ncsw/inc/Peripherals/fm_mac_ext.h> -#include <contrib/ncsw/inc/Peripherals/fm_port_ext.h> -#include <contrib/ncsw/inc/flib/fsl_fman_dtsec.h> -#include <contrib/ncsw/inc/xx_ext.h> - +#include "dpaa_eth.h" #include "fman.h" +#include "fman_port.h" #include "if_dtsec.h" -#include "if_dtsec_im.h" -#include "if_dtsec_rm.h" + +#include "fman_if.h" +#include "fman_port_if.h" #define DTSEC_MIN_FRAME_SIZE 64 #define DTSEC_MAX_FRAME_SIZE 9600 #define DTSEC_REG_MAXFRM 0x110 -#define DTSEC_REG_GADDR(i) (0x0a0 + 4*(i)) +#define DTSEC_REG_IGADDR(i) (0x080 + 4 * (i)) +#define DTSEC_REG_GADDR(i) (0x0a0 + 4 * (i)) -/** - * @group dTSEC private defines. - * @{ - */ -/** - * dTSEC FMan MAC exceptions info struct. - */ -struct dtsec_fm_mac_ex_str { - const int num; - const char *str; -}; -/** @} */ +#define DTSEC_ECNTRL 0x014 +#define ECNTRL_R100M 0x00000008 +#define DTSEC_TCTRL 0x040 +#define TCTRL_GTS 0x00000020 +#define DTSEC_RCTRL 0x050 +#define RCTRL_CFA 0x00008000 +#define RCTRL_GHTX 0x00000400 +#define RCTRL_GRS 0x00000020 +#define RCTRL_MPROM 0x00000008 +#define DTSEC_MACCFG1 0x100 +#define DTSEC_MACCFG2 0x104 +#define MACCFG_IF_M 0x00000300 +#define MACCFG_IF_10_100 0x00000100 +#define MACCFG_IF_1G 0x00000200 +#define MACCFG_FULLDUPLEX 0x00000001 +#define DTSEC_MACSTNADDR1 0x140 +#define DTSEC_MACSTNADDR2 0x144 +static void dtsec_if_init_locked(struct dtsec_softc *sc); /** * @group FMan MAC routines. * @{ */ -#define DTSEC_MAC_EXCEPTIONS_END (-1) - -/** - * FMan MAC exceptions. - */ -static const struct dtsec_fm_mac_ex_str dtsec_fm_mac_exceptions[] = { - { e_FM_MAC_EX_10G_MDIO_SCAN_EVENTMDIO, "MDIO scan event" }, - { e_FM_MAC_EX_10G_MDIO_CMD_CMPL, "MDIO command completion" }, - { e_FM_MAC_EX_10G_REM_FAULT, "Remote fault" }, - { e_FM_MAC_EX_10G_LOC_FAULT, "Local fault" }, - { e_FM_MAC_EX_10G_1TX_ECC_ER, "Transmit frame ECC error" }, - { e_FM_MAC_EX_10G_TX_FIFO_UNFL, "Transmit FIFO underflow" }, - { e_FM_MAC_EX_10G_TX_FIFO_OVFL, "Receive FIFO overflow" }, - { e_FM_MAC_EX_10G_TX_ER, "Transmit frame error" }, - { e_FM_MAC_EX_10G_RX_FIFO_OVFL, "Receive FIFO overflow" }, - { e_FM_MAC_EX_10G_RX_ECC_ER, "Receive frame ECC error" }, - { e_FM_MAC_EX_10G_RX_JAB_FRM, "Receive jabber frame" }, - { e_FM_MAC_EX_10G_RX_OVRSZ_FRM, "Receive oversized frame" }, - { e_FM_MAC_EX_10G_RX_RUNT_FRM, "Receive runt frame" }, - { e_FM_MAC_EX_10G_RX_FRAG_FRM, "Receive fragment frame" }, - { e_FM_MAC_EX_10G_RX_LEN_ER, "Receive payload length error" }, - { e_FM_MAC_EX_10G_RX_CRC_ER, "Receive CRC error" }, - { e_FM_MAC_EX_10G_RX_ALIGN_ER, "Receive alignment error" }, - { e_FM_MAC_EX_1G_BAB_RX, "Babbling receive error" }, - { e_FM_MAC_EX_1G_RX_CTL, "Receive control (pause frame) interrupt" }, - { e_FM_MAC_EX_1G_GRATEFUL_TX_STP_COMPLET, "Graceful transmit stop " - "complete" }, - { e_FM_MAC_EX_1G_BAB_TX, "Babbling transmit error" }, - { e_FM_MAC_EX_1G_TX_CTL, "Transmit control (pause frame) interrupt" }, - { e_FM_MAC_EX_1G_TX_ERR, "Transmit error" }, - { e_FM_MAC_EX_1G_LATE_COL, "Late collision" }, - { e_FM_MAC_EX_1G_COL_RET_LMT, "Collision retry limit" }, - { e_FM_MAC_EX_1G_TX_FIFO_UNDRN, "Transmit FIFO underrun" }, - { e_FM_MAC_EX_1G_MAG_PCKT, "Magic Packet detected when dTSEC is in " - "Magic Packet detection mode" }, - { e_FM_MAC_EX_1G_MII_MNG_RD_COMPLET, "MII management read completion" }, - { e_FM_MAC_EX_1G_MII_MNG_WR_COMPLET, "MII management write completion" }, - { e_FM_MAC_EX_1G_GRATEFUL_RX_STP_COMPLET, "Graceful receive stop " - "complete" }, - { e_FM_MAC_EX_1G_TX_DATA_ERR, "Internal data error on transmit" }, - { e_FM_MAC_EX_1G_RX_DATA_ERR, "Internal data error on receive" }, - { e_FM_MAC_EX_1G_1588_TS_RX_ERR, "Time-Stamp Receive Error" }, - { e_FM_MAC_EX_1G_RX_MIB_CNT_OVFL, "MIB counter overflow" }, - { DTSEC_MAC_EXCEPTIONS_END, "" } -}; - -static const char * -dtsec_fm_mac_ex_to_str(e_FmMacExceptions exception) -{ - int i; - - for (i = 0; dtsec_fm_mac_exceptions[i].num != exception && - dtsec_fm_mac_exceptions[i].num != DTSEC_MAC_EXCEPTIONS_END; ++i) - ; - - if (dtsec_fm_mac_exceptions[i].num == DTSEC_MAC_EXCEPTIONS_END) - return ("<Unknown Exception>"); - - return (dtsec_fm_mac_exceptions[i].str); -} - -static void -dtsec_fm_mac_mdio_event_callback(t_Handle h_App, - e_FmMacExceptions exception) -{ - struct dtsec_softc *sc; - - sc = h_App; - device_printf(sc->sc_dev, "MDIO event %i: %s.\n", exception, - dtsec_fm_mac_ex_to_str(exception)); -} - -static void -dtsec_fm_mac_exception_callback(t_Handle app, e_FmMacExceptions exception) -{ - struct dtsec_softc *sc; - - sc = app; - device_printf(sc->sc_dev, "MAC exception %i: %s.\n", exception, - dtsec_fm_mac_ex_to_str(exception)); -} - -static void -dtsec_fm_mac_free(struct dtsec_softc *sc) -{ - if (sc->sc_mach == NULL) - return; - - FM_MAC_Disable(sc->sc_mach, e_COMM_MODE_RX_AND_TX); - FM_MAC_Free(sc->sc_mach); - sc->sc_mach = NULL; -} static int dtsec_fm_mac_init(struct dtsec_softc *sc, uint8_t *mac) { - t_FmMacParams params; - t_Error error; - - memset(¶ms, 0, sizeof(params)); - memcpy(¶ms.addr, mac, sizeof(params.addr)); - - params.baseAddr = rman_get_bushandle(sc->sc_mem); - params.enetMode = sc->sc_mac_enet_mode; - params.macId = sc->sc_eth_id; - params.mdioIrq = sc->sc_mac_mdio_irq; - params.f_Event = dtsec_fm_mac_mdio_event_callback; - params.f_Exception = dtsec_fm_mac_exception_callback; - params.h_App = sc; - params.h_Fm = sc->sc_fmh; + FMAN_GET_REVISION(device_get_parent(sc->sc_base.sc_dev), &sc->sc_base.sc_rev_major, + &sc->sc_base.sc_rev_minor); - sc->sc_mach = FM_MAC_Config(¶ms); - if (sc->sc_mach == NULL) { - device_printf(sc->sc_dev, "couldn't configure FM_MAC module.\n" - ); + if (FMAN_RESET_MAC(device_get_parent(sc->sc_base.sc_dev), sc->sc_base.sc_eth_id) != 0) return (ENXIO); - } - - error = FM_MAC_ConfigResetOnInit(sc->sc_mach, TRUE); - if (error != E_OK) { - device_printf(sc->sc_dev, "couldn't enable reset on init " - "feature.\n"); - dtsec_fm_mac_free(sc); - return (ENXIO); - } - - /* Do not inform about pause frames */ - error = FM_MAC_ConfigException(sc->sc_mach, e_FM_MAC_EX_1G_RX_CTL, - FALSE); - if (error != E_OK) { - device_printf(sc->sc_dev, "couldn't disable pause frames " - "exception.\n"); - dtsec_fm_mac_free(sc); - return (ENXIO); - } - - error = FM_MAC_Init(sc->sc_mach); - if (error != E_OK) { - device_printf(sc->sc_dev, "couldn't initialize FM_MAC module." - "\n"); - dtsec_fm_mac_free(sc); - return (ENXIO); - } return (0); } @@ -239,87 +109,6 @@ dtsec_fm_mac_init(struct dtsec_softc *sc, uint8_t *mac) /** - * @group FMan PORT routines. - * @{ - */ -static const char * -dtsec_fm_port_ex_to_str(e_FmPortExceptions exception) -{ - - switch (exception) { - case e_FM_PORT_EXCEPTION_IM_BUSY: - return ("IM: RX busy"); - default: - return ("<Unknown Exception>"); - } -} - -void -dtsec_fm_port_rx_exception_callback(t_Handle app, - e_FmPortExceptions exception) -{ - struct dtsec_softc *sc; - - sc = app; - device_printf(sc->sc_dev, "RX exception: %i: %s.\n", exception, - dtsec_fm_port_ex_to_str(exception)); -} - -void -dtsec_fm_port_tx_exception_callback(t_Handle app, - e_FmPortExceptions exception) -{ - struct dtsec_softc *sc; - - sc = app; - device_printf(sc->sc_dev, "TX exception: %i: %s.\n", exception, - dtsec_fm_port_ex_to_str(exception)); -} - -e_FmPortType -dtsec_fm_port_rx_type(enum eth_dev_type type) -{ - switch (type) { - case ETH_DTSEC: - return (e_FM_PORT_TYPE_RX); - case ETH_10GSEC: - return (e_FM_PORT_TYPE_RX_10G); - default: - return (e_FM_PORT_TYPE_DUMMY); - } -} - -e_FmPortType -dtsec_fm_port_tx_type(enum eth_dev_type type) -{ - - switch (type) { - case ETH_DTSEC: - return (e_FM_PORT_TYPE_TX); - case ETH_10GSEC: - return (e_FM_PORT_TYPE_TX_10G); - default: - return (e_FM_PORT_TYPE_DUMMY); - } -} - -static void -dtsec_fm_port_free_both(struct dtsec_softc *sc) -{ - if (sc->sc_rxph) { - FM_PORT_Free(sc->sc_rxph); - sc->sc_rxph = NULL; - } - - if (sc->sc_txph) { - FM_PORT_Free(sc->sc_txph); - sc->sc_txph = NULL; - } -} -/** @} */ - - -/** * @group IFnet routines. * @{ */ @@ -332,7 +121,7 @@ dtsec_set_mtu(struct dtsec_softc *sc, unsigned int mtu) DTSEC_LOCK_ASSERT(sc); if (mtu >= DTSEC_MIN_FRAME_SIZE && mtu <= DTSEC_MAX_FRAME_SIZE) { - bus_write_4(sc->sc_mem, DTSEC_REG_MAXFRM, mtu); + bus_write_4(sc->sc_base.sc_mem, DTSEC_REG_MAXFRM, mtu); return (mtu); } @@ -342,9 +131,10 @@ dtsec_set_mtu(struct dtsec_softc *sc, unsigned int mtu) static u_int dtsec_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) { - struct dtsec_softc *sc = arg; + uint32_t h, *hashtable = arg; - FM_MAC_AddHashMacAddr(sc->sc_mach, (t_EnetAddr *)LLADDR(sdl)); + h = (ether_crc32_be(LLADDR(sdl), ETHER_ADDR_LEN) >> 24) & 0xFF; + hashtable[(h >> 5)] |= 1 << (0x1F - (h & 0x1F)); return (1); } @@ -352,18 +142,52 @@ dtsec_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) static void dtsec_setup_multicast(struct dtsec_softc *sc) { + uint32_t hashtable[8] = {}; int i; - if (if_getflags(sc->sc_ifnet) & IFF_ALLMULTI) { + if (if_getflags(sc->sc_base.sc_ifnet) & IFF_ALLMULTI) { for (i = 0; i < 8; i++) - bus_write_4(sc->sc_mem, DTSEC_REG_GADDR(i), 0xFFFFFFFF); + bus_write_4(sc->sc_base.sc_mem, DTSEC_REG_GADDR(i), 0xFFFFFFFF); + bus_write_4(sc->sc_base.sc_mem, DTSEC_RCTRL, + bus_read_4(sc->sc_base.sc_mem, DTSEC_RCTRL) | RCTRL_MPROM); return; } + bus_write_4(sc->sc_base.sc_mem, DTSEC_RCTRL, + bus_read_4(sc->sc_base.sc_mem, DTSEC_RCTRL) & ~RCTRL_MPROM); + + if_foreach_llmaddr(sc->sc_base.sc_ifnet, dtsec_hash_maddr, hashtable); + for (i = 0; i < 8; i++) + bus_write_4(sc->sc_base.sc_mem, DTSEC_REG_GADDR(i), + hashtable[i]); +} + +static void +dtsec_if_graceful_stop(struct dtsec_softc *sc) +{ + bus_write_4(sc->sc_base.sc_mem, DTSEC_RCTRL, + bus_read_4(sc->sc_base.sc_mem, DTSEC_RCTRL) | RCTRL_GRS); + if (sc->sc_base.sc_rev_major == 2) + DELAY(100); + else + DELAY(10); - fman_dtsec_reset_filter_table(rman_get_virtual(sc->sc_mem), - true, false); - if_foreach_llmaddr(sc->sc_ifnet, dtsec_hash_maddr, sc); + bus_write_4(sc->sc_base.sc_mem, DTSEC_TCTRL, + bus_read_4(sc->sc_base.sc_mem, DTSEC_TCTRL) | TCTRL_GTS); +} + +static void +dtsec_if_graceful_start(struct dtsec_softc *sc) +{ + bus_write_4(sc->sc_base.sc_mem, DTSEC_RCTRL, + bus_read_4(sc->sc_base.sc_mem, DTSEC_RCTRL) & ~RCTRL_GRS); + if (sc->sc_base.sc_rev_major == 2) + DELAY(100); + else + DELAY(10); + + bus_write_4(sc->sc_base.sc_mem, DTSEC_TCTRL, + bus_read_4(sc->sc_base.sc_mem, DTSEC_TCTRL) & ~TCTRL_GTS); } static int @@ -373,24 +197,22 @@ dtsec_if_enable_locked(struct dtsec_softc *sc) DTSEC_LOCK_ASSERT(sc); - error = FM_MAC_Enable(sc->sc_mach, e_COMM_MODE_RX_AND_TX); - if (error != E_OK) - return (EIO); + dtsec_if_graceful_start(sc); - error = FM_PORT_Enable(sc->sc_rxph); - if (error != E_OK) + error = FMAN_PORT_ENABLE(sc->sc_base.sc_rx_port); + if (error != 0) return (EIO); - error = FM_PORT_Enable(sc->sc_txph); - if (error != E_OK) + error = FMAN_PORT_ENABLE(sc->sc_base.sc_tx_port); + if (error != 0) return (EIO); dtsec_setup_multicast(sc); - if_setdrvflagbits(sc->sc_ifnet, IFF_DRV_RUNNING, 0); + if_setdrvflagbits(sc->sc_base.sc_ifnet, IFF_DRV_RUNNING, 0); /* Refresh link state */ - dtsec_miibus_statchg(sc->sc_dev); + dtsec_miibus_statchg(sc->sc_base.sc_dev); return (0); } @@ -402,19 +224,17 @@ dtsec_if_disable_locked(struct dtsec_softc *sc) DTSEC_LOCK_ASSERT(sc); - error = FM_MAC_Disable(sc->sc_mach, e_COMM_MODE_RX_AND_TX); - if (error != E_OK) - return (EIO); + dtsec_if_graceful_stop(sc); - error = FM_PORT_Disable(sc->sc_rxph); - if (error != E_OK) + error = FMAN_PORT_DISABLE(sc->sc_base.sc_rx_port); + if (error != 0) return (EIO); - error = FM_PORT_Disable(sc->sc_txph); - if (error != E_OK) + error = FMAN_PORT_DISABLE(sc->sc_base.sc_tx_port); + if (error != 0) return (EIO); - if_setdrvflagbits(sc->sc_ifnet, 0, IFF_DRV_RUNNING); + if_setdrvflagbits(sc->sc_base.sc_ifnet, 0, IFF_DRV_RUNNING); return (0); } @@ -443,9 +263,10 @@ dtsec_if_ioctl(if_t ifp, u_long command, caddr_t data) case SIOCSIFFLAGS: DTSEC_LOCK(sc); - if (if_getflags(sc->sc_ifnet) & IFF_UP) - error = dtsec_if_enable_locked(sc); - else + if (if_getflags(ifp) & IFF_UP) { + if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) + dtsec_if_init_locked(sc); + } else error = dtsec_if_disable_locked(sc); DTSEC_UNLOCK(sc); @@ -453,7 +274,7 @@ dtsec_if_ioctl(if_t ifp, u_long command, caddr_t data) case SIOCGIFMEDIA: case SIOCSIFMEDIA: - error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii->mii_media, + error = ifmedia_ioctl(ifp, ifr, &sc->sc_base.sc_mii->mii_media, command); break; @@ -474,8 +295,8 @@ dtsec_if_tick(void *arg) /* TODO */ DTSEC_LOCK(sc); - mii_tick(sc->sc_mii); - callout_reset(&sc->sc_tick_callout, hz, dtsec_if_tick, sc); + mii_tick(sc->sc_base.sc_mii); + callout_reset(&sc->sc_base.sc_tick_callout, hz, dtsec_if_tick, sc); DTSEC_UNLOCK(sc); } @@ -487,30 +308,38 @@ dtsec_if_deinit_locked(struct dtsec_softc *sc) DTSEC_LOCK_ASSERT(sc); DTSEC_UNLOCK(sc); - callout_drain(&sc->sc_tick_callout); + callout_drain(&sc->sc_base.sc_tick_callout); DTSEC_LOCK(sc); } static void +dtsec_if_set_macaddr(struct dtsec_softc *sc, const char *addr) +{ + uint32_t reg; + + reg = (addr[5] << 24) | (addr[4] << 16) | (addr[3] << 8) | addr[2]; + bus_write_4(sc->sc_base.sc_mem, DTSEC_MACSTNADDR1, reg); + reg = (addr[1] << 24) | (addr[0] << 16); + bus_write_4(sc->sc_base.sc_mem, DTSEC_MACSTNADDR2, reg); +} + +static void dtsec_if_init_locked(struct dtsec_softc *sc) { int error; + const char *macaddr; DTSEC_LOCK_ASSERT(sc); - /* Set MAC address */ - error = FM_MAC_ModifyMacAddr(sc->sc_mach, - (t_EnetAddr *)if_getlladdr(sc->sc_ifnet)); - if (error != E_OK) { - device_printf(sc->sc_dev, "couldn't set MAC address.\n"); - goto err; - } + macaddr = if_getlladdr(sc->sc_base.sc_ifnet); + dtsec_if_set_macaddr(sc, macaddr); /* Start MII polling */ - if (sc->sc_mii) - callout_reset(&sc->sc_tick_callout, hz, dtsec_if_tick, sc); + if (sc->sc_base.sc_mii) + callout_reset(&sc->sc_base.sc_tick_callout, hz, + dtsec_if_tick, sc); - if (if_getflags(sc->sc_ifnet) & IFF_UP) { + if (if_getflags(sc->sc_base.sc_ifnet) & IFF_UP) { error = dtsec_if_enable_locked(sc); if (error != 0) goto err; @@ -524,7 +353,7 @@ dtsec_if_init_locked(struct dtsec_softc *sc) err: dtsec_if_deinit_locked(sc); - device_printf(sc->sc_dev, "initialization error.\n"); + device_printf(sc->sc_base.sc_dev, "initialization error.\n"); return; } @@ -547,7 +376,7 @@ dtsec_if_start(if_t ifp) sc = if_getsoftc(ifp); DTSEC_LOCK(sc); - sc->sc_start_locked(sc); + dpaa_eth_if_start_locked(&sc->sc_base); DTSEC_UNLOCK(sc); } @@ -569,7 +398,7 @@ dtsec_ifmedia_upd(if_t ifp) struct dtsec_softc *sc = if_getsoftc(ifp); DTSEC_LOCK(sc); - mii_mediachg(sc->sc_mii); + mii_mediachg(sc->sc_base.sc_mii); DTSEC_UNLOCK(sc); return (0); @@ -582,10 +411,10 @@ dtsec_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr) DTSEC_LOCK(sc); - mii_pollstat(sc->sc_mii); + mii_pollstat(sc->sc_base.sc_mii); - ifmr->ifm_active = sc->sc_mii->mii_media_active; - ifmr->ifm_status = sc->sc_mii->mii_media_status; + ifmr->ifm_active = sc->sc_base.sc_mii->mii_media_active; + ifmr->ifm_status = sc->sc_base.sc_mii->mii_media_status; DTSEC_UNLOCK(sc); } @@ -596,118 +425,75 @@ dtsec_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr) * @group dTSEC bus interface. * @{ */ -static void -dtsec_configure_mode(struct dtsec_softc *sc) -{ - char tunable[64]; - - snprintf(tunable, sizeof(tunable), "%s.independent_mode", - device_get_nameunit(sc->sc_dev)); - - sc->sc_mode = DTSEC_MODE_REGULAR; - TUNABLE_INT_FETCH(tunable, &sc->sc_mode); - - if (sc->sc_mode == DTSEC_MODE_REGULAR) { - sc->sc_port_rx_init = dtsec_rm_fm_port_rx_init; - sc->sc_port_tx_init = dtsec_rm_fm_port_tx_init; - sc->sc_start_locked = dtsec_rm_if_start_locked; - } else { - sc->sc_port_rx_init = dtsec_im_fm_port_rx_init; - sc->sc_port_tx_init = dtsec_im_fm_port_tx_init; - sc->sc_start_locked = dtsec_im_if_start_locked; - } - - device_printf(sc->sc_dev, "Configured for %s mode.\n", - (sc->sc_mode == DTSEC_MODE_REGULAR) ? "regular" : "independent"); -} int dtsec_attach(device_t dev) { struct dtsec_softc *sc; - device_t parent; + cell_t ports[2]; + phandle_t node; int error; if_t ifp; sc = device_get_softc(dev); - parent = device_get_parent(dev); - sc->sc_dev = dev; - sc->sc_mac_mdio_irq = NO_IRQ; - - /* Check if MallocSmart allocator is ready */ - if (XX_MallocSmartInit() != E_OK) - return (ENXIO); + sc->sc_base.sc_dev = dev; + node = ofw_bus_get_node(dev); /* Init locks */ - mtx_init(&sc->sc_lock, device_get_nameunit(dev), + mtx_init(&sc->sc_base.sc_lock, device_get_nameunit(dev), "DTSEC Global Lock", MTX_DEF); - mtx_init(&sc->sc_mii_lock, device_get_nameunit(dev), + mtx_init(&sc->sc_base.sc_mii_lock, device_get_nameunit(dev), "DTSEC MII Lock", MTX_DEF); /* Init callouts */ - callout_init(&sc->sc_tick_callout, CALLOUT_MPSAFE); + callout_init(&sc->sc_base.sc_tick_callout, CALLOUT_MPSAFE); - /* Read configuraton */ - if ((error = fman_get_handle(parent, &sc->sc_fmh)) != 0) - return (error); - - if ((error = fman_get_muram_handle(parent, &sc->sc_muramh)) != 0) - return (error); - - if ((error = fman_get_bushandle(parent, &sc->sc_fm_base)) != 0) - return (error); - - /* Configure working mode */ - dtsec_configure_mode(sc); + /* Create RX buffer pool */ + error = dpaa_eth_pool_rx_init(&sc->sc_base); + if (error != 0) + return (EIO); - /* If we are working in regular mode configure BMAN and QMAN */ - if (sc->sc_mode == DTSEC_MODE_REGULAR) { - /* Create RX buffer pool */ - error = dtsec_rm_pool_rx_init(sc); - if (error != 0) - return (EIO); + /* Create RX frame queue range */ + error = dpaa_eth_fq_rx_init(&sc->sc_base); + if (error != 0) + return (EIO); - /* Create RX frame queue range */ - error = dtsec_rm_fqr_rx_init(sc); - if (error != 0) - return (EIO); + /* Create frame info pool */ + error = dpaa_eth_fi_pool_init(&sc->sc_base); + if (error != 0) + return (EIO); - /* Create frame info pool */ - error = dtsec_rm_fi_pool_init(sc); - if (error != 0) - return (EIO); + /* Create TX frame queue range */ + error = dpaa_eth_fq_tx_init(&sc->sc_base); + if (error != 0) + return (EIO); - /* Create TX frame queue range */ - error = dtsec_rm_fqr_tx_init(sc); - if (error != 0) - return (EIO); + if (OF_getencprop(node, "fsl,fman-ports", ports, sizeof(ports)) < 0) { + device_printf(dev, "missing ports in device tree\n"); + return (ENXIO); } - /* Init FMan MAC module. */ - error = dtsec_fm_mac_init(sc, sc->sc_mac_addr); + error = dtsec_fm_mac_init(sc, sc->sc_base.sc_mac_addr); if (error != 0) { dtsec_detach(dev); return (ENXIO); } - /* Init FMan TX port */ - error = sc->sc_port_tx_init(sc, device_get_unit(sc->sc_dev)); - if (error != 0) { - dtsec_detach(dev); - return (ENXIO); - } + sc->sc_base.sc_rx_port = OF_device_from_xref(ports[0]); + sc->sc_base.sc_tx_port = OF_device_from_xref(ports[1]); + dpaa_eth_fm_port_rx_init(&sc->sc_base); + dpaa_eth_fm_port_tx_init(&sc->sc_base); - /* Init FMan RX port */ - error = sc->sc_port_rx_init(sc, device_get_unit(sc->sc_dev)); - if (error != 0) { + if (sc->sc_base.sc_rx_port == NULL || sc->sc_base.sc_tx_port == NULL) { + device_printf(dev, "invalid ports"); dtsec_detach(dev); return (ENXIO); } /* Create network interface for upper layers */ - ifp = sc->sc_ifnet = if_alloc(IFT_ETHER); + ifp = sc->sc_base.sc_ifnet = if_alloc(IFT_ETHER); if_setsoftc(ifp, sc); if_setflags(ifp, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST); @@ -716,11 +502,12 @@ dtsec_attach(device_t dev) if_setioctlfn(ifp, dtsec_if_ioctl); if_setsendqlen(ifp, IFQ_MAXLEN); - if (sc->sc_phy_addr >= 0) - if_initname(ifp, device_get_name(sc->sc_dev), - device_get_unit(sc->sc_dev)); + if (sc->sc_base.sc_phy_addr >= 0) + if_initname(ifp, device_get_name(sc->sc_base.sc_dev), + device_get_unit(sc->sc_base.sc_dev)); else - if_initname(ifp, "dtsec_phy", device_get_unit(sc->sc_dev)); + if_initname(ifp, "dtsec_phy", + device_get_unit(sc->sc_base.sc_dev)); /* TODO */ #if 0 @@ -732,18 +519,18 @@ dtsec_attach(device_t dev) if_setcapenable(ifp, if_getcapabilities(ifp)); /* Attach PHY(s) */ - error = mii_attach(sc->sc_dev, &sc->sc_mii_dev, ifp, dtsec_ifmedia_upd, - dtsec_ifmedia_sts, BMSR_DEFCAPMASK, sc->sc_phy_addr, - MII_OFFSET_ANY, 0); + error = mii_attach(sc->sc_base.sc_dev, &sc->sc_base.sc_mii_dev, + ifp, dtsec_ifmedia_upd, dtsec_ifmedia_sts, BMSR_DEFCAPMASK, + sc->sc_base.sc_phy_addr, MII_OFFSET_ANY, 0); if (error) { - device_printf(sc->sc_dev, "attaching PHYs failed: %d\n", error); - dtsec_detach(sc->sc_dev); + device_printf(sc->sc_base.sc_dev, + "attaching PHYs failed: %d\n", error); + dtsec_detach(sc->sc_base.sc_dev); return (error); } - sc->sc_mii = device_get_softc(sc->sc_mii_dev); /* Attach to stack */ - ether_ifattach(ifp, sc->sc_mac_addr); + ether_ifattach(ifp, sc->sc_base.sc_mac_addr); return (0); } @@ -755,7 +542,7 @@ dtsec_detach(device_t dev) if_t ifp; sc = device_get_softc(dev); - ifp = sc->sc_ifnet; + ifp = sc->sc_base.sc_ifnet; if (device_is_attached(dev)) { ether_ifdetach(ifp); @@ -765,28 +552,23 @@ dtsec_detach(device_t dev) DTSEC_UNLOCK(sc); } - if (sc->sc_ifnet) { - if_free(sc->sc_ifnet); - sc->sc_ifnet = NULL; + if (sc->sc_base.sc_ifnet) { + if_free(sc->sc_base.sc_ifnet); + sc->sc_base.sc_ifnet = NULL; } - if (sc->sc_mode == DTSEC_MODE_REGULAR) { - /* Free RX/TX FQRs */ - dtsec_rm_fqr_rx_free(sc); - dtsec_rm_fqr_tx_free(sc); + /* Free RX/TX FQRs */ + dpaa_eth_fq_rx_free(&sc->sc_base); + dpaa_eth_fq_tx_free(&sc->sc_base); - /* Free frame info pool */ - dtsec_rm_fi_pool_free(sc); + /* Free frame info pool */ + dpaa_eth_fi_pool_free(&sc->sc_base); - /* Free RX buffer pool */ - dtsec_rm_pool_rx_free(sc); - } - - dtsec_fm_mac_free(sc); - dtsec_fm_port_free_both(sc); + /* Free RX buffer pool */ + dpaa_eth_pool_rx_free(&sc->sc_base); /* Destroy lock */ - mtx_destroy(&sc->sc_lock); + mtx_destroy(&sc->sc_base.sc_lock); return (0); } @@ -825,7 +607,7 @@ dtsec_miibus_readreg(device_t dev, int phy, int reg) sc = device_get_softc(dev); - return (MIIBUS_READREG(sc->sc_mdio, phy, reg)); + return (MIIBUS_READREG(sc->sc_base.sc_mdio, phy, reg)); } int @@ -836,43 +618,49 @@ dtsec_miibus_writereg(device_t dev, int phy, int reg, int value) sc = device_get_softc(dev); - return (MIIBUS_WRITEREG(sc->sc_mdio, phy, reg, value)); + return (MIIBUS_WRITEREG(sc->sc_base.sc_mdio, phy, reg, value)); } void dtsec_miibus_statchg(device_t dev) { struct dtsec_softc *sc; - e_EnetSpeed speed; + uint32_t reg; bool duplex; - int error; + int speed; sc = device_get_softc(dev); DTSEC_LOCK_ASSERT(sc); - duplex = ((sc->sc_mii->mii_media_active & IFM_GMASK) == IFM_FDX); + duplex = ((sc->sc_base.sc_mii->mii_media_active & IFM_GMASK) == IFM_FDX); - switch (IFM_SUBTYPE(sc->sc_mii->mii_media_active)) { + switch (IFM_SUBTYPE(sc->sc_base.sc_mii->mii_media_active)) { case IFM_1000_T: case IFM_1000_SX: - speed = e_ENET_SPEED_1000; - break; - - case IFM_100_TX: - speed = e_ENET_SPEED_100; - break; - - case IFM_10_T: - speed = e_ENET_SPEED_10; + if (!duplex) { + device_printf(sc->sc_base.sc_dev, + "Only full-duplex supported for 1Gbps speeds"); + return; + } + speed = MACCFG_IF_1G; break; default: - speed = e_ENET_SPEED_10; + speed = MACCFG_IF_10_100; } - error = FM_MAC_AdjustLink(sc->sc_mach, speed, duplex); - if (error != E_OK) - device_printf(sc->sc_dev, "error while adjusting MAC speed.\n"); + reg = bus_read_4(sc->sc_base.sc_mem, DTSEC_MACCFG2); + reg &= ~(MACCFG_IF_M | MACCFG_FULLDUPLEX); + + if (duplex) + reg |= MACCFG_FULLDUPLEX; + reg |= speed; + bus_write_4(sc->sc_base.sc_mem, DTSEC_MACCFG2, reg); + + reg = bus_read_4(sc->sc_base.sc_mem, DTSEC_ECNTRL) & ~ECNTRL_R100M; + if (IFM_SUBTYPE(sc->sc_base.sc_mii->mii_media_active) == IFM_100_TX) + reg |= ECNTRL_R100M; + bus_write_4(sc->sc_base.sc_mem, DTSEC_ECNTRL, reg); } /** @} */ diff --git a/sys/dev/dpaa/if_dtsec.h b/sys/dev/dpaa/if_dtsec.h index 4de0b776e9f5..7e0cb52a2400 100644 --- a/sys/dev/dpaa/if_dtsec.h +++ b/sys/dev/dpaa/if_dtsec.h @@ -34,11 +34,11 @@ #define DTSEC_MODE_REGULAR 0 #define DTSEC_MODE_INDEPENDENT 1 -#define DTSEC_LOCK(sc) mtx_lock(&(sc)->sc_lock) -#define DTSEC_UNLOCK(sc) mtx_unlock(&(sc)->sc_lock) -#define DTSEC_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_lock, MA_OWNED) -#define DTSEC_MII_LOCK(sc) mtx_lock(&(sc)->sc_mii_lock) -#define DTSEC_MII_UNLOCK(sc) mtx_unlock(&(sc)->sc_mii_lock) +#define DTSEC_LOCK(sc) mtx_lock(&(sc)->sc_base.sc_lock) +#define DTSEC_UNLOCK(sc) mtx_unlock(&(sc)->sc_base.sc_lock) +#define DTSEC_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_base.sc_lock, MA_OWNED) +#define DTSEC_MII_LOCK(sc) mtx_lock(&(sc)->sc_base.sc_mii_lock) +#define DTSEC_MII_UNLOCK(sc) mtx_unlock(&(sc)->sc_base.sc_mii_lock) enum eth_dev_type { ETH_DTSEC = 0x1, @@ -46,97 +46,13 @@ enum eth_dev_type { }; struct dtsec_softc { - /* XXX MII bus requires that struct ifnet is first!!! */ - if_t sc_ifnet; - - device_t sc_dev; - struct resource *sc_mem; - struct mtx sc_lock; - int sc_mode; - - /* Methods */ - int (*sc_port_rx_init) - (struct dtsec_softc *sc, int unit); - int (*sc_port_tx_init) - (struct dtsec_softc *sc, int unit); - void (*sc_start_locked) - (struct dtsec_softc *sc); - - /* dTSEC data */ + struct dpaa_eth_softc sc_base; enum eth_dev_type sc_eth_dev_type; - uint8_t sc_eth_id; /* Ethernet ID within its frame manager */ - uintptr_t sc_mac_mem_offset; - e_EnetMode sc_mac_enet_mode; - int sc_mac_mdio_irq; - uint8_t sc_mac_addr[6]; - int sc_port_rx_hw_id; - int sc_port_tx_hw_id; - uint32_t sc_port_tx_qman_chan; - int sc_phy_addr; - bool sc_hidden; - device_t sc_mdio; - - /* Params from fman_bus driver */ - vm_offset_t sc_fm_base; - t_Handle sc_fmh; - t_Handle sc_muramh; - - t_Handle sc_mach; - t_Handle sc_rxph; - t_Handle sc_txph; - - /* MII data */ - struct mii_data *sc_mii; - device_t sc_mii_dev; - struct mtx sc_mii_lock; - - struct callout sc_tick_callout; - - /* RX Pool */ - t_Handle sc_rx_pool; - uint8_t sc_rx_bpid; - uma_zone_t sc_rx_zone; - char sc_rx_zname[64]; - - /* RX Frame Queue */ - t_Handle sc_rx_fqr; - uint32_t sc_rx_fqid; - - /* TX Frame Queue */ - t_Handle sc_tx_fqr; - bool sc_tx_fqr_full; - t_Handle sc_tx_conf_fqr; - uint32_t sc_tx_conf_fqid; - - /* Frame Info Zone */ - uma_zone_t sc_fi_zone; - char sc_fi_zname[64]; }; /** @} */ /** - * @group dTSEC FMan PORT API. - * @{ - */ -enum dtsec_fm_port_params { - FM_PORT_LIODN_BASE = 0, - FM_PORT_LIODN_OFFSET = 0, - FM_PORT_MEM_ID = 0, - FM_PORT_MEM_ATTR = MEMORY_ATTR_CACHEABLE, - FM_PORT_BUFFER_SIZE = MCLBYTES, -}; - -e_FmPortType dtsec_fm_port_rx_type(enum eth_dev_type type); -void dtsec_fm_port_rx_exception_callback(t_Handle app, - e_FmPortExceptions exception); -void dtsec_fm_port_tx_exception_callback(t_Handle app, - e_FmPortExceptions exception); -e_FmPortType dtsec_fm_port_tx_type(enum eth_dev_type type); -/** @} */ - - -/** * @group dTSEC bus interface. * @{ */ diff --git a/sys/dev/dpaa/if_dtsec_fdt.c b/sys/dev/dpaa/if_dtsec_fdt.c index 441ff9c96c50..85b1998015d5 100644 --- a/sys/dev/dpaa/if_dtsec_fdt.c +++ b/sys/dev/dpaa/if_dtsec_fdt.c @@ -48,9 +48,7 @@ #include "miibus_if.h" -#include <contrib/ncsw/inc/Peripherals/fm_port_ext.h> -#include <contrib/ncsw/inc/xx_ext.h> - +#include "dpaa_eth.h" #include "if_dtsec.h" #include "fman.h" @@ -123,7 +121,7 @@ dtsec_fdt_attach(device_t dev) enet_node = ofw_bus_get_node(dev); if (OF_getprop(enet_node, "local-mac-address", - (void *)sc->sc_mac_addr, 6) == -1) { + (void *)sc->sc_base.sc_mac_addr, 6) == -1) { device_printf(dev, "Could not load local-mac-addr property from DTS\n"); return (ENXIO); @@ -135,17 +133,17 @@ dtsec_fdt_attach(device_t dev) else if (ofw_bus_is_compatible(dev, "fsl,fman-xgec") != 0) sc->sc_eth_dev_type = ETH_10GSEC; else - return(ENXIO); + return (ENXIO); /* Get PHY address */ - if (OF_getprop(enet_node, "phy-handle", (void *)&phy_node, + if (OF_getprop(enet_node, "tbi-handle", (void *)&phy_node, sizeof(phy_node)) <= 0) return (ENXIO); phy_node = OF_node_from_xref(phy_node); - if (OF_getprop(phy_node, "reg", (void *)&sc->sc_phy_addr, - sizeof(sc->sc_phy_addr)) <= 0) + if (OF_getprop(phy_node, "reg", (void *)&sc->sc_base.sc_phy_addr, + sizeof(sc->sc_base.sc_phy_addr)) <= 0) return (ENXIO); phy_dev = OF_device_from_xref(OF_parent(phy_node)); @@ -155,12 +153,12 @@ dtsec_fdt_attach(device_t dev) return (ENXIO); } - sc->sc_mdio = phy_dev; + sc->sc_base.sc_mdio = phy_dev; /* Get MAC memory offset in SoC */ rid = 0; - sc->sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); - if (sc->sc_mem == NULL) + sc->sc_base.sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); + if (sc->sc_base.sc_mem == NULL) return (ENXIO); /* Get PHY connection type */ @@ -168,20 +166,10 @@ dtsec_fdt_attach(device_t dev) sizeof(phy_type)) <= 0) return (ENXIO); - if (!strcmp(phy_type, "sgmii")) - sc->sc_mac_enet_mode = e_ENET_MODE_SGMII_1000; - else if (!strcmp(phy_type, "rgmii")) - sc->sc_mac_enet_mode = e_ENET_MODE_RGMII_1000; - else if (!strcmp(phy_type, "xgmii")) - /* We set 10 Gigabit mode flag however we don't support it */ - sc->sc_mac_enet_mode = e_ENET_MODE_XGMII_10000; - else - return (ENXIO); - if (OF_getencprop(enet_node, "cell-index", (void *)&mac_id, sizeof(mac_id)) <= 0) return (ENXIO); - sc->sc_eth_id = mac_id; + sc->sc_base.sc_eth_id = mac_id; /* Get RX/TX port handles */ if (OF_getprop(enet_node, "fsl,fman-ports", (void *)fman_rxtx_node, @@ -194,32 +182,17 @@ dtsec_fdt_attach(device_t dev) if (fman_rxtx_node[1] == 0) return (ENXIO); - fman_rxtx_node[0] = OF_instance_to_package(fman_rxtx_node[0]); - fman_rxtx_node[1] = OF_instance_to_package(fman_rxtx_node[1]); - - if (ofw_bus_node_is_compatible(fman_rxtx_node[0], - "fsl,fman-v2-port-rx") == 0) - return (ENXIO); - - if (ofw_bus_node_is_compatible(fman_rxtx_node[1], - "fsl,fman-v2-port-tx") == 0) - return (ENXIO); - - /* Get RX port HW id */ - if (OF_getprop(fman_rxtx_node[0], "reg", (void *)&sc->sc_port_rx_hw_id, - sizeof(sc->sc_port_rx_hw_id)) <= 0) - return (ENXIO); + sc->sc_base.sc_rx_port = OF_device_from_xref(fman_rxtx_node[0]); + sc->sc_base.sc_tx_port = OF_device_from_xref(fman_rxtx_node[1]); - /* Get TX port HW id */ - if (OF_getprop(fman_rxtx_node[1], "reg", (void *)&sc->sc_port_tx_hw_id, - sizeof(sc->sc_port_tx_hw_id)) <= 0) + if (sc->sc_base.sc_rx_port == NULL || sc->sc_base.sc_tx_port == NULL) return (ENXIO); if (OF_getprop(fman_rxtx_node[1], "cell-index", &fman_tx_cell, sizeof(fman_tx_cell)) <= 0) return (ENXIO); /* Get QMan channel */ - sc->sc_port_tx_qman_chan = fman_qman_channel_id(device_get_parent(dev), + sc->sc_base.sc_port_tx_qman_chan = fman_qman_channel_id(device_get_parent(dev), fman_tx_cell); return (dtsec_attach(dev)); diff --git a/sys/dev/dpaa/if_dtsec_im.c b/sys/dev/dpaa/if_dtsec_im.c deleted file mode 100644 index 0711275790c3..000000000000 --- a/sys/dev/dpaa/if_dtsec_im.c +++ /dev/null @@ -1,260 +0,0 @@ -/*- - * Copyright (c) 2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/bus.h> -#include <sys/rman.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/socket.h> -#include <sys/sysctl.h> -#include <sys/sockio.h> - -#include <net/ethernet.h> -#include <net/if.h> -#include <net/if_dl.h> -#include <net/if_media.h> -#include <net/if_types.h> -#include <net/if_arp.h> - -#include <dev/mii/mii.h> -#include <dev/mii/miivar.h> - -#include "miibus_if.h" - -#include <contrib/ncsw/inc/integrations/dpaa_integration_ext.h> -#include <contrib/ncsw/inc/Peripherals/fm_mac_ext.h> -#include <contrib/ncsw/inc/Peripherals/fm_port_ext.h> -#include <contrib/ncsw/inc/xx_ext.h> - -#include "fman.h" -#include "if_dtsec.h" -#include "if_dtsec_im.h" - - -/** - * @group dTSEC FMan PORT routines. - * @{ - */ -static e_RxStoreResponse -dtsec_im_fm_port_rx_callback(t_Handle app, uint8_t *data, uint16_t length, - uint16_t status, uint8_t position, t_Handle buf_context) -{ - struct dtsec_softc *sc; - struct mbuf *m; - - /* TODO STATUS / Position checking */ - sc = app; - - m = m_devget(data, length, 0, sc->sc_ifnet, NULL); - if (m) - if_input(sc->sc_ifnet, m); - - XX_FreeSmart(data); - - return (e_RX_STORE_RESPONSE_CONTINUE); -} - -static void -dtsec_im_fm_port_tx_conf_callback(t_Handle app, uint8_t *data, uint16_t status, - t_Handle buf_context) -{ - - /* TODO: Check status */ - XX_FreeSmart(data); -} - -static uint8_t * -dtsec_im_fm_port_rx_get_buf(t_Handle buffer_pool, t_Handle *buf_context_handle) -{ - struct dtsec_softc *sc; - uint8_t *buffer; - - sc = buffer_pool; - - buffer = XX_MallocSmart(FM_PORT_BUFFER_SIZE, 0, sizeof(void *)); - if (!buffer) - device_printf(sc->sc_dev, "couldn't allocate RX buffer.\n"); - - return (buffer); -} - -static t_Error -dtsec_im_fm_port_rx_put_buf(t_Handle buffer_pool, uint8_t *buffer, - t_Handle buf_context) -{ - - XX_FreeSmart(buffer); - return (E_OK); -} - -int -dtsec_im_fm_port_rx_init(struct dtsec_softc *sc, int unit) -{ - t_FmPortParams params; - t_BufferPoolInfo *pool_params; - t_FmPortImRxTxParams *im_params; - t_Error error; - - memset(¶ms, 0, sizeof(params)); - - params.baseAddr = sc->sc_fm_base + sc->sc_port_rx_hw_id; - params.h_Fm = sc->sc_fmh; - params.portType = dtsec_fm_port_rx_type(sc->sc_eth_dev_type); - params.portId = sc->sc_eth_id; - params.independentModeEnable = TRUE; - params.liodnBase = FM_PORT_LIODN_BASE; - params.f_Exception = dtsec_fm_port_rx_exception_callback; - params.h_App = sc; - - im_params = ¶ms.specificParams.imRxTxParams; - im_params->h_FmMuram = sc->sc_muramh; - im_params->liodnOffset = FM_PORT_LIODN_OFFSET; - im_params->dataMemId = FM_PORT_MEM_ID; - im_params->dataMemAttributes = FM_PORT_MEM_ATTR; - im_params->f_RxStore = dtsec_im_fm_port_rx_callback; - - pool_params = ¶ms.specificParams.imRxTxParams.rxPoolParams; - pool_params->h_BufferPool = sc; - pool_params->f_GetBuf = dtsec_im_fm_port_rx_get_buf; - pool_params->f_PutBuf = dtsec_im_fm_port_rx_put_buf; - pool_params->bufferSize = FM_PORT_BUFFER_SIZE; - - sc->sc_rxph = FM_PORT_Config(¶ms); - if (sc->sc_rxph == NULL) { - device_printf(sc->sc_dev, "couldn't configure FM Port RX.\n"); - return (ENXIO); - } - - error = FM_PORT_Init(sc->sc_rxph); - if (error != E_OK) { - device_printf(sc->sc_dev, "couldn't initialize FM Port RX.\n"); - FM_PORT_Free(sc->sc_rxph); - return (ENXIO); - } - - if (bootverbose) - device_printf(sc->sc_dev, "RX hw port 0x%02x initialized.\n", - sc->sc_port_rx_hw_id); - - return (0); -} - -int -dtsec_im_fm_port_tx_init(struct dtsec_softc *sc, int unit) -{ - t_FmPortParams params; - t_FmPortImRxTxParams *im_params; - t_Error error; - - memset(¶ms, 0, sizeof(params)); - - params.baseAddr = sc->sc_fm_base + sc->sc_port_tx_hw_id; - params.h_Fm = sc->sc_fmh; - params.portType = dtsec_fm_port_tx_type(sc->sc_eth_dev_type); - params.portId = unit; - params.independentModeEnable = TRUE; - params.liodnBase = FM_PORT_LIODN_BASE; - params.f_Exception = dtsec_fm_port_tx_exception_callback; - params.h_App = sc; - - im_params = ¶ms.specificParams.imRxTxParams; - im_params->h_FmMuram = sc->sc_muramh; - im_params->liodnOffset = FM_PORT_LIODN_OFFSET; - im_params->dataMemId = FM_PORT_MEM_ID; - im_params->dataMemAttributes = FM_PORT_MEM_ATTR; - im_params->f_TxConf = dtsec_im_fm_port_tx_conf_callback; - - sc->sc_txph = FM_PORT_Config(¶ms); - if (sc->sc_txph == NULL) { - device_printf(sc->sc_dev, "couldn't configure FM Port TX.\n"); - return (ENXIO); - } - - error = FM_PORT_Init(sc->sc_txph); - if (error != E_OK) { - device_printf(sc->sc_dev, "couldn't initialize FM Port TX.\n"); - FM_PORT_Free(sc->sc_txph); - return (ENXIO); - } - - if (bootverbose) - device_printf(sc->sc_dev, "TX hw port 0x%02x initialized.\n", - sc->sc_port_tx_hw_id); - - return (0); -} -/** @} */ - - -/** - * @group dTSEC IFnet routines. - * @{ - */ -void -dtsec_im_if_start_locked(struct dtsec_softc *sc) -{ - uint8_t *buffer; - uint16_t length; - struct mbuf *m; - int error; - - DTSEC_LOCK_ASSERT(sc); - /* TODO: IFF_DRV_OACTIVE */ - - if ((sc->sc_mii->mii_media_status & IFM_ACTIVE) == 0) - return; - - if ((if_getdrvflags(sc->sc_ifnet) & IFF_DRV_RUNNING) != IFF_DRV_RUNNING) - return; - - while (!if_sendq_empty(sc->sc_ifnet)) { - m = if_dequeue(sc->sc_ifnet); - if (m == NULL) - break; - - length = m_length(m, NULL); - buffer = XX_MallocSmart(length, 0, sizeof(void *)); - if (!buffer) { - m_freem(m); - break; - } - - m_copydata(m, 0, length, buffer); - m_freem(m); - - error = FM_PORT_ImTx(sc->sc_txph, buffer, length, TRUE, buffer); - if (error != E_OK) { - /* TODO: Ring full */ - XX_FreeSmart(buffer); - break; - } - } -} -/** @} */ diff --git a/sys/dev/dpaa/if_dtsec_im.h b/sys/dev/dpaa/if_dtsec_im.h deleted file mode 100644 index e1c8f2a3c0c2..000000000000 --- a/sys/dev/dpaa/if_dtsec_im.h +++ /dev/null @@ -1,39 +0,0 @@ -/*- - * Copyright (c) 2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef IF_DTSEC_IM_H_ -#define IF_DTSEC_IM_H_ - -/** - * @group dTSEC Independent Mode API. - * @{ - */ -int dtsec_im_fm_port_tx_init(struct dtsec_softc *sc, int unit); -int dtsec_im_fm_port_rx_init(struct dtsec_softc *sc, int unit); -void dtsec_im_if_start_locked(struct dtsec_softc *sc); -/** @} */ - -#endif /* IF_DTSEC_IM_H_ */ diff --git a/sys/dev/dpaa/if_dtsec_rm.c b/sys/dev/dpaa/if_dtsec_rm.c deleted file mode 100644 index 0b9f8e0ae6c7..000000000000 --- a/sys/dev/dpaa/if_dtsec_rm.c +++ /dev/null @@ -1,651 +0,0 @@ -/*- - * Copyright (c) 2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/kernel.h> -#include <sys/module.h> -#include <sys/bus.h> -#include <sys/rman.h> -#include <sys/malloc.h> -#include <sys/mbuf.h> -#include <sys/socket.h> -#include <sys/sysctl.h> -#include <sys/sockio.h> - -#include <net/ethernet.h> -#include <net/if.h> -#include <net/if_dl.h> -#include <net/if_media.h> -#include <net/if_types.h> -#include <net/if_arp.h> - -#include <dev/mii/mii.h> -#include <dev/mii/miivar.h> - -#include "miibus_if.h" - -#include <contrib/ncsw/inc/integrations/dpaa_integration_ext.h> -#include <contrib/ncsw/inc/Peripherals/fm_ext.h> -#include <contrib/ncsw/inc/Peripherals/fm_mac_ext.h> -#include <contrib/ncsw/inc/Peripherals/fm_port_ext.h> -#include <contrib/ncsw/inc/xx_ext.h> - -#include "fman.h" -#include "bman.h" -#include "qman.h" -#include "if_dtsec.h" -#include "if_dtsec_rm.h" - - -/** - * @group dTSEC RM private defines. - * @{ - */ -#define DTSEC_BPOOLS_USED (1) -#define DTSEC_MAX_TX_QUEUE_LEN 256 - -struct dtsec_rm_frame_info { - struct mbuf *fi_mbuf; - t_DpaaSGTE fi_sgt[DPAA_NUM_OF_SG_TABLE_ENTRY]; -}; - -enum dtsec_rm_pool_params { - DTSEC_RM_POOL_RX_LOW_MARK = 16, - DTSEC_RM_POOL_RX_HIGH_MARK = 64, - DTSEC_RM_POOL_RX_MAX_SIZE = 256, - - DTSEC_RM_POOL_FI_LOW_MARK = 16, - DTSEC_RM_POOL_FI_HIGH_MARK = 64, - DTSEC_RM_POOL_FI_MAX_SIZE = 256, -}; - -#define DTSEC_RM_FQR_RX_CHANNEL e_QM_FQ_CHANNEL_POOL1 -#define DTSEC_RM_FQR_TX_CONF_CHANNEL e_QM_FQ_CHANNEL_SWPORTAL0 -enum dtsec_rm_fqr_params { - DTSEC_RM_FQR_RX_WQ = 1, - DTSEC_RM_FQR_TX_WQ = 1, - DTSEC_RM_FQR_TX_CONF_WQ = 1 -}; -/** @} */ - - -/** - * @group dTSEC Frame Info routines. - * @{ - */ -void -dtsec_rm_fi_pool_free(struct dtsec_softc *sc) -{ - - if (sc->sc_fi_zone != NULL) - uma_zdestroy(sc->sc_fi_zone); -} - -int -dtsec_rm_fi_pool_init(struct dtsec_softc *sc) -{ - - snprintf(sc->sc_fi_zname, sizeof(sc->sc_fi_zname), "%s: Frame Info", - device_get_nameunit(sc->sc_dev)); - - sc->sc_fi_zone = uma_zcreate(sc->sc_fi_zname, - sizeof(struct dtsec_rm_frame_info), NULL, NULL, NULL, NULL, - UMA_ALIGN_PTR, 0); - - return (0); -} - -static struct dtsec_rm_frame_info * -dtsec_rm_fi_alloc(struct dtsec_softc *sc) -{ - struct dtsec_rm_frame_info *fi; - - fi = uma_zalloc(sc->sc_fi_zone, M_NOWAIT); - - return (fi); -} - -static void -dtsec_rm_fi_free(struct dtsec_softc *sc, struct dtsec_rm_frame_info *fi) -{ - - uma_zfree(sc->sc_fi_zone, fi); -} -/** @} */ - - -/** - * @group dTSEC FMan PORT routines. - * @{ - */ -int -dtsec_rm_fm_port_rx_init(struct dtsec_softc *sc, int unit) -{ - t_FmPortParams params; - t_FmPortRxParams *rx_params; - t_FmExtPools *pool_params; - t_Error error; - - memset(¶ms, 0, sizeof(params)); - - params.baseAddr = sc->sc_fm_base + sc->sc_port_rx_hw_id; - params.h_Fm = sc->sc_fmh; - params.portType = dtsec_fm_port_rx_type(sc->sc_eth_dev_type); - params.portId = sc->sc_eth_id; - params.independentModeEnable = false; - params.liodnBase = FM_PORT_LIODN_BASE; - params.f_Exception = dtsec_fm_port_rx_exception_callback; - params.h_App = sc; - - rx_params = ¶ms.specificParams.rxParams; - rx_params->errFqid = sc->sc_rx_fqid; - rx_params->dfltFqid = sc->sc_rx_fqid; - rx_params->liodnOffset = 0; - - pool_params = &rx_params->extBufPools; - pool_params->numOfPoolsUsed = DTSEC_BPOOLS_USED; - pool_params->extBufPool->id = sc->sc_rx_bpid; - pool_params->extBufPool->size = FM_PORT_BUFFER_SIZE; - - sc->sc_rxph = FM_PORT_Config(¶ms); - if (sc->sc_rxph == NULL) { - device_printf(sc->sc_dev, "couldn't configure FM Port RX.\n"); - return (ENXIO); - } - - error = FM_PORT_Init(sc->sc_rxph); - if (error != E_OK) { - device_printf(sc->sc_dev, "couldn't initialize FM Port RX.\n"); - FM_PORT_Free(sc->sc_rxph); - return (ENXIO); - } - - if (bootverbose) - device_printf(sc->sc_dev, "RX hw port 0x%02x initialized.\n", - sc->sc_port_rx_hw_id); - - return (0); -} - -int -dtsec_rm_fm_port_tx_init(struct dtsec_softc *sc, int unit) -{ - t_FmPortParams params; - t_FmPortNonRxParams *tx_params; - t_Error error; - - memset(¶ms, 0, sizeof(params)); - - params.baseAddr = sc->sc_fm_base + sc->sc_port_tx_hw_id; - params.h_Fm = sc->sc_fmh; - params.portType = dtsec_fm_port_tx_type(sc->sc_eth_dev_type); - params.portId = sc->sc_eth_id; - params.independentModeEnable = false; - params.liodnBase = FM_PORT_LIODN_BASE; - params.f_Exception = dtsec_fm_port_tx_exception_callback; - params.h_App = sc; - - tx_params = ¶ms.specificParams.nonRxParams; - tx_params->errFqid = sc->sc_tx_conf_fqid; - tx_params->dfltFqid = sc->sc_tx_conf_fqid; - tx_params->qmChannel = sc->sc_port_tx_qman_chan; -#ifdef FM_OP_PARTITION_ERRATA_FMANx8 - tx_params->opLiodnOffset = 0; -#endif - - sc->sc_txph = FM_PORT_Config(¶ms); - if (sc->sc_txph == NULL) { - device_printf(sc->sc_dev, "couldn't configure FM Port TX.\n"); - return (ENXIO); - } - - error = FM_PORT_Init(sc->sc_txph); - if (error != E_OK) { - device_printf(sc->sc_dev, "couldn't initialize FM Port TX.\n"); - FM_PORT_Free(sc->sc_txph); - return (ENXIO); - } - - if (bootverbose) - device_printf(sc->sc_dev, "TX hw port 0x%02x initialized.\n", - sc->sc_port_tx_hw_id); - - return (0); -} -/** @} */ - - -/** - * @group dTSEC buffer pools routines. - * @{ - */ -static t_Error -dtsec_rm_pool_rx_put_buffer(t_Handle h_BufferPool, uint8_t *buffer, - t_Handle context) -{ - struct dtsec_softc *sc; - - sc = h_BufferPool; - uma_zfree(sc->sc_rx_zone, buffer); - - return (E_OK); -} - -static uint8_t * -dtsec_rm_pool_rx_get_buffer(t_Handle h_BufferPool, t_Handle *context) -{ - struct dtsec_softc *sc; - uint8_t *buffer; - - sc = h_BufferPool; - buffer = uma_zalloc(sc->sc_rx_zone, M_NOWAIT); - - return (buffer); -} - -static void -dtsec_rm_pool_rx_depleted(t_Handle h_App, bool in) -{ - struct dtsec_softc *sc; - unsigned int count; - - sc = h_App; - - if (!in) - return; - - while (1) { - count = bman_count(sc->sc_rx_pool); - if (count > DTSEC_RM_POOL_RX_HIGH_MARK) - return; - - bman_pool_fill(sc->sc_rx_pool, DTSEC_RM_POOL_RX_HIGH_MARK); - } -} - -void -dtsec_rm_pool_rx_free(struct dtsec_softc *sc) -{ - - if (sc->sc_rx_pool != NULL) - bman_pool_destroy(sc->sc_rx_pool); - - if (sc->sc_rx_zone != NULL) - uma_zdestroy(sc->sc_rx_zone); -} - -int -dtsec_rm_pool_rx_init(struct dtsec_softc *sc) -{ - - /* FM_PORT_BUFFER_SIZE must be less than PAGE_SIZE */ - CTASSERT(FM_PORT_BUFFER_SIZE < PAGE_SIZE); - - snprintf(sc->sc_rx_zname, sizeof(sc->sc_rx_zname), "%s: RX Buffers", - device_get_nameunit(sc->sc_dev)); - - sc->sc_rx_zone = uma_zcreate(sc->sc_rx_zname, FM_PORT_BUFFER_SIZE, NULL, - NULL, NULL, NULL, FM_PORT_BUFFER_SIZE - 1, 0); - - sc->sc_rx_pool = bman_pool_create(&sc->sc_rx_bpid, FM_PORT_BUFFER_SIZE, - 0, 0, DTSEC_RM_POOL_RX_MAX_SIZE, dtsec_rm_pool_rx_get_buffer, - dtsec_rm_pool_rx_put_buffer, DTSEC_RM_POOL_RX_LOW_MARK, - DTSEC_RM_POOL_RX_HIGH_MARK, 0, 0, dtsec_rm_pool_rx_depleted, sc, NULL, - NULL); - if (sc->sc_rx_pool == NULL) { - device_printf(sc->sc_dev, "NULL rx pool somehow\n"); - dtsec_rm_pool_rx_free(sc); - return (EIO); - } - - return (0); -} -/** @} */ - - -/** - * @group dTSEC Frame Queue Range routines. - * @{ - */ -static void -dtsec_rm_fqr_mext_free(struct mbuf *m) -{ - struct dtsec_softc *sc; - void *buffer; - - buffer = m->m_ext.ext_arg1; - sc = m->m_ext.ext_arg2; - if (bman_count(sc->sc_rx_pool) <= DTSEC_RM_POOL_RX_MAX_SIZE) - bman_put_buffer(sc->sc_rx_pool, buffer); - else - dtsec_rm_pool_rx_put_buffer(sc, buffer, NULL); -} - -static e_RxStoreResponse -dtsec_rm_fqr_rx_callback(t_Handle app, t_Handle fqr, t_Handle portal, - uint32_t fqid_off, t_DpaaFD *frame) -{ - struct dtsec_softc *sc; - struct mbuf *m; - void *frame_va; - - m = NULL; - sc = app; - - frame_va = DPAA_FD_GET_ADDR(frame); - KASSERT(DPAA_FD_GET_FORMAT(frame) == e_DPAA_FD_FORMAT_TYPE_SHORT_SBSF, - ("%s(): Got unsupported frame format 0x%02X!", __func__, - DPAA_FD_GET_FORMAT(frame))); - - KASSERT(DPAA_FD_GET_OFFSET(frame) == 0, - ("%s(): Only offset 0 is supported!", __func__)); - - if (DPAA_FD_GET_STATUS(frame) != 0) { - device_printf(sc->sc_dev, "RX error: 0x%08X\n", - DPAA_FD_GET_STATUS(frame)); - goto err; - } - - m = m_gethdr(M_NOWAIT, MT_HEADER); - if (m == NULL) - goto err; - - m_extadd(m, frame_va, FM_PORT_BUFFER_SIZE, - dtsec_rm_fqr_mext_free, frame_va, sc, 0, - EXT_NET_DRV); - - m->m_pkthdr.rcvif = sc->sc_ifnet; - m->m_len = DPAA_FD_GET_LENGTH(frame); - m_fixhdr(m); - - if_input(sc->sc_ifnet, m); - - return (e_RX_STORE_RESPONSE_CONTINUE); - -err: - bman_put_buffer(sc->sc_rx_pool, frame_va); - if (m != NULL) - m_freem(m); - - return (e_RX_STORE_RESPONSE_CONTINUE); -} - -static e_RxStoreResponse -dtsec_rm_fqr_tx_confirm_callback(t_Handle app, t_Handle fqr, t_Handle portal, - uint32_t fqid_off, t_DpaaFD *frame) -{ - struct dtsec_rm_frame_info *fi; - struct dtsec_softc *sc; - unsigned int qlen; - t_DpaaSGTE *sgt0; - - sc = app; - - if (DPAA_FD_GET_STATUS(frame) != 0) - device_printf(sc->sc_dev, "TX error: 0x%08X\n", - DPAA_FD_GET_STATUS(frame)); - - /* - * We are storing struct dtsec_rm_frame_info in first entry - * of scatter-gather table. - */ - sgt0 = DPAA_FD_GET_ADDR(frame); - fi = DPAA_SGTE_GET_ADDR(sgt0); - - /* Free transmitted frame */ - m_freem(fi->fi_mbuf); - dtsec_rm_fi_free(sc, fi); - - qlen = qman_fqr_get_counter(sc->sc_tx_conf_fqr, 0, - e_QM_FQR_COUNTERS_FRAME); - - if (qlen == 0) { - DTSEC_LOCK(sc); - - if (sc->sc_tx_fqr_full) { - sc->sc_tx_fqr_full = 0; - dtsec_rm_if_start_locked(sc); - } - - DTSEC_UNLOCK(sc); - } - - return (e_RX_STORE_RESPONSE_CONTINUE); -} - -void -dtsec_rm_fqr_rx_free(struct dtsec_softc *sc) -{ - - if (sc->sc_rx_fqr) - qman_fqr_free(sc->sc_rx_fqr); -} - -int -dtsec_rm_fqr_rx_init(struct dtsec_softc *sc) -{ - t_Error error; - t_Handle fqr; - - /* Default Frame Queue */ - fqr = qman_fqr_create(1, DTSEC_RM_FQR_RX_CHANNEL, DTSEC_RM_FQR_RX_WQ, - false, 0, false, false, true, false, 0, 0, 0); - if (fqr == NULL) { - device_printf(sc->sc_dev, "could not create default RX queue" - "\n"); - return (EIO); - } - - sc->sc_rx_fqr = fqr; - sc->sc_rx_fqid = qman_fqr_get_base_fqid(fqr); - - error = qman_fqr_register_cb(fqr, dtsec_rm_fqr_rx_callback, sc); - if (error != E_OK) { - device_printf(sc->sc_dev, "could not register RX callback\n"); - dtsec_rm_fqr_rx_free(sc); - return (EIO); - } - - return (0); -} - -void -dtsec_rm_fqr_tx_free(struct dtsec_softc *sc) -{ - - if (sc->sc_tx_fqr) - qman_fqr_free(sc->sc_tx_fqr); - - if (sc->sc_tx_conf_fqr) - qman_fqr_free(sc->sc_tx_conf_fqr); -} - -int -dtsec_rm_fqr_tx_init(struct dtsec_softc *sc) -{ - t_Error error; - t_Handle fqr; - - /* TX Frame Queue */ - fqr = qman_fqr_create(1, sc->sc_port_tx_qman_chan, - DTSEC_RM_FQR_TX_WQ, false, 0, false, false, true, false, 0, 0, 0); - if (fqr == NULL) { - device_printf(sc->sc_dev, "could not create default TX queue" - "\n"); - return (EIO); - } - - sc->sc_tx_fqr = fqr; - - /* TX Confirmation Frame Queue */ - fqr = qman_fqr_create(1, DTSEC_RM_FQR_TX_CONF_CHANNEL, - DTSEC_RM_FQR_TX_CONF_WQ, false, 0, false, false, true, false, 0, 0, - 0); - if (fqr == NULL) { - device_printf(sc->sc_dev, "could not create TX confirmation " - "queue\n"); - dtsec_rm_fqr_tx_free(sc); - return (EIO); - } - - sc->sc_tx_conf_fqr = fqr; - sc->sc_tx_conf_fqid = qman_fqr_get_base_fqid(fqr); - - error = qman_fqr_register_cb(fqr, dtsec_rm_fqr_tx_confirm_callback, sc); - if (error != E_OK) { - device_printf(sc->sc_dev, "could not register TX confirmation " - "callback\n"); - dtsec_rm_fqr_tx_free(sc); - return (EIO); - } - - return (0); -} -/** @} */ - - -/** - * @group dTSEC IFnet routines. - * @{ - */ -void -dtsec_rm_if_start_locked(struct dtsec_softc *sc) -{ - vm_size_t dsize, psize, ssize; - struct dtsec_rm_frame_info *fi; - unsigned int qlen, i; - struct mbuf *m0, *m; - vm_offset_t vaddr; - t_DpaaFD fd; - - DTSEC_LOCK_ASSERT(sc); - /* TODO: IFF_DRV_OACTIVE */ - - if ((sc->sc_mii->mii_media_status & IFM_ACTIVE) == 0) - return; - - if ((if_getdrvflags(sc->sc_ifnet) & IFF_DRV_RUNNING) != IFF_DRV_RUNNING) - return; - - while (!if_sendq_empty(sc->sc_ifnet)) { - /* Check length of the TX queue */ - qlen = qman_fqr_get_counter(sc->sc_tx_fqr, 0, - e_QM_FQR_COUNTERS_FRAME); - - if (qlen >= DTSEC_MAX_TX_QUEUE_LEN) { - sc->sc_tx_fqr_full = 1; - return; - } - - fi = dtsec_rm_fi_alloc(sc); - if (fi == NULL) - return; - - m0 = if_dequeue(sc->sc_ifnet); - if (m0 == NULL) { - dtsec_rm_fi_free(sc, fi); - return; - } - - i = 0; - m = m0; - psize = 0; - dsize = 0; - fi->fi_mbuf = m0; - while (m && i < DPAA_NUM_OF_SG_TABLE_ENTRY) { - if (m->m_len == 0) - continue; - - /* - * First entry in scatter-gather table is used to keep - * pointer to frame info structure. - */ - DPAA_SGTE_SET_ADDR(&fi->fi_sgt[i], (void *)fi); - DPAA_SGTE_SET_LENGTH(&fi->fi_sgt[i], 0); - - DPAA_SGTE_SET_EXTENSION(&fi->fi_sgt[i], 0); - DPAA_SGTE_SET_FINAL(&fi->fi_sgt[i], 0); - DPAA_SGTE_SET_BPID(&fi->fi_sgt[i], 0); - DPAA_SGTE_SET_OFFSET(&fi->fi_sgt[i], 0); - i++; - - dsize = m->m_len; - vaddr = (vm_offset_t)m->m_data; - while (dsize > 0 && i < DPAA_NUM_OF_SG_TABLE_ENTRY) { - ssize = PAGE_SIZE - (vaddr & PAGE_MASK); - if (m->m_len < ssize) - ssize = m->m_len; - - DPAA_SGTE_SET_ADDR(&fi->fi_sgt[i], - (void *)vaddr); - DPAA_SGTE_SET_LENGTH(&fi->fi_sgt[i], ssize); - - DPAA_SGTE_SET_EXTENSION(&fi->fi_sgt[i], 0); - DPAA_SGTE_SET_FINAL(&fi->fi_sgt[i], 0); - DPAA_SGTE_SET_BPID(&fi->fi_sgt[i], 0); - DPAA_SGTE_SET_OFFSET(&fi->fi_sgt[i], 0); - - dsize -= ssize; - vaddr += ssize; - psize += ssize; - i++; - } - - if (dsize > 0) - break; - - m = m->m_next; - } - - /* Check if SG table was constructed properly */ - if (m != NULL || dsize != 0) { - dtsec_rm_fi_free(sc, fi); - m_freem(m0); - continue; - } - - DPAA_SGTE_SET_FINAL(&fi->fi_sgt[i-1], 1); - - DPAA_FD_SET_ADDR(&fd, fi->fi_sgt); - DPAA_FD_SET_LENGTH(&fd, psize); - DPAA_FD_SET_FORMAT(&fd, e_DPAA_FD_FORMAT_TYPE_SHORT_MBSF); - - fd.liodn = 0; - fd.bpid = 0; - fd.elion = 0; - DPAA_FD_SET_OFFSET(&fd, 0); - DPAA_FD_SET_STATUS(&fd, 0); - - DTSEC_UNLOCK(sc); - if (qman_fqr_enqueue(sc->sc_tx_fqr, 0, &fd) != E_OK) { - dtsec_rm_fi_free(sc, fi); - m_freem(m0); - } - DTSEC_LOCK(sc); - } -} -/** @} */ diff --git a/sys/dev/dpaa/if_dtsec_rm.h b/sys/dev/dpaa/if_dtsec_rm.h deleted file mode 100644 index 28f779a11386..000000000000 --- a/sys/dev/dpaa/if_dtsec_rm.h +++ /dev/null @@ -1,51 +0,0 @@ -/*- - * Copyright (c) 2012 Semihalf. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef IF_DTSEC_RM_H_ -#define IF_DTSEC_RM_H_ - -/** - * @group dTSEC Regular Mode API. - * @{ - */ -int dtsec_rm_fm_port_rx_init(struct dtsec_softc *sc, int unit); -int dtsec_rm_fm_port_tx_init(struct dtsec_softc *sc, int unit); - -void dtsec_rm_if_start_locked(struct dtsec_softc *sc); - -int dtsec_rm_pool_rx_init(struct dtsec_softc *sc); -void dtsec_rm_pool_rx_free(struct dtsec_softc *sc); - -int dtsec_rm_fi_pool_init(struct dtsec_softc *sc); -void dtsec_rm_fi_pool_free(struct dtsec_softc *sc); - -int dtsec_rm_fqr_rx_init(struct dtsec_softc *sc); -int dtsec_rm_fqr_tx_init(struct dtsec_softc *sc); -void dtsec_rm_fqr_rx_free(struct dtsec_softc *sc); -void dtsec_rm_fqr_tx_free(struct dtsec_softc *sc); -/** @} */ - -#endif /* IF_DTSEC_RM_H_ */ diff --git a/sys/dev/dpaa/if_memac.c b/sys/dev/dpaa/if_memac.c new file mode 100644 index 000000000000..6d0fa3f5e337 --- /dev/null +++ b/sys/dev/dpaa/if_memac.c @@ -0,0 +1,820 @@ +/* + * Copyright (c) 2026 Justin Hibbits + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/mbuf.h> +#include <sys/module.h> +#include <sys/rman.h> +#include <sys/socket.h> +#include <sys/sysctl.h> +#include <sys/sockio.h> + +#include <machine/bus.h> +#include <machine/resource.h> + +#include <net/ethernet.h> +#include <net/if.h> +#include <net/if_dl.h> +#include <net/if_media.h> +#include <net/if_types.h> +#include <net/if_arp.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> +#include <dev/ofw/openfirm.h> + +#include "miibus_if.h" + +#include "dpaa_eth.h" +#include "fman.h" +#include "fman_port.h" +#include "if_memac.h" + +#include "fman_if.h" +#include "fman_port_if.h" + +#define MEMAC_MIN_FRAME_SIZE 64 +#define MEMAC_MAX_FRAME_SIZE 32736 + +#define MEMAC_COMMAND_CONFIG 0x008 +#define COMMAND_CONFIG_RXSTP 0x20000000 +#define COMMAND_CONFIG_NO_LEN_CHK 0x00020000 +#define COMMAND_CONFIG_SWR 0x00001000 +#define COMMAND_CONFIG_TXP 0x00000800 +#define COMMAND_CONFIG_CRC 0x00000040 +#define COMMAND_CONFIG_PROMISC 0x00000010 +#define COMMAND_CONFIG_RX_EN 0x00000002 +#define COMMAND_CONFIG_TX_EN 0x00000001 +#define MEMAC_MAC_ADDR_0 0x00c +#define MEMAC_MAC_ADDR_1 0x010 +#define MEMAC_REG_MAXFRM 0x14 +#define MEMAC_REG_TX_FIFO_SECTIONS 0x020 +#define TX_FIFO_SECTIONS_TX_EMPTY_M 0xffff0000 +#define TX_FIFO_SECTIONS_TX_EMPTY_S 16 +#define TX_FIFO_SECTIONS_TX_AVAIL_M 0x0000ffff + +#define HASHTABLE_CTRL 0x02c +#define CTRL_MCAST 0x00000100 +#define CTRL_HASH_ADDR_M 0x0000003f +#define HASHTABLE_SIZE 64 +#define MEMAC_IEVENT 0x040 +#define IEVENT_RX_EMPTY 0x00000040 +#define IEVENT_TX_EMPTY 0x00000020 +#define MEMAC_CL01_PAUSE_QUANTA 0x054 +#define MEMAC_IF_MODE 0x300 +#define IF_MODE_ENA 0x00008000 +#define IF_MODE_SSP_M 0x00006000 +#define IF_MODE_SSP_100MB 0x00000000 +#define IF_MODE_SSP_10MB 0x00002000 +#define IF_MODE_SSP_1GB 0x00004000 +#define IF_MODE_SFD 0x00001000 +#define IF_MODE_MSG 0x00000200 +#define IF_MODE_HG 0x00000100 +#define IF_MODE_HD 0x00000040 +#define IF_MODE_RLP 0x00000020 +#define IF_MODE_RG 0x00000004 +#define IF_MODE_IFMODE_M 0x00000003 +#define IF_MODE_IFMODE_XGMII 0x00000000 +#define IF_MODE_IFMODE_MII 0x00000001 +#define IF_MODE_IFMODE_GMII 0x00000002 + +#define DEFAULT_PAUSE_QUANTA 0xf000 + +#define DPAA_CSUM_TX_OFFLOAD (CSUM_IP | CSUM_DELAY_DATA | CSUM_DELAY_DATA_IPV6) + + +/** + * @group FMan MAC routines. + * @{ + */ +#define MEMAC_MAC_EXCEPTIONS_END (-1) + +static void memac_if_init_locked(struct memac_softc *sc); + +static int +memac_fm_mac_init(struct memac_softc *sc, uint8_t *mac) +{ + uint32_t reg; + + FMAN_GET_REVISION(device_get_parent(sc->sc_base.sc_dev), &sc->sc_base.sc_rev_major, + &sc->sc_base.sc_rev_minor); + + if (FMAN_RESET_MAC(device_get_parent(sc->sc_base.sc_dev), sc->sc_base.sc_eth_id) != 0) + return (ENXIO); + + reg = bus_read_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG); + reg |= COMMAND_CONFIG_SWR; + bus_write_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG, reg); + + while (bus_read_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG) & COMMAND_CONFIG_SWR) + ; + + /* TODO: TX_FIFO_SECTIONS */ + /* TODO: CL01 pause quantum */ + bus_write_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG, + COMMAND_CONFIG_NO_LEN_CHK | COMMAND_CONFIG_TXP | COMMAND_CONFIG_CRC); + + reg = bus_read_4(sc->sc_base.sc_mem, MEMAC_IF_MODE); + reg &= ~(IF_MODE_IFMODE_M | IF_MODE_RG); + switch (sc->sc_base.sc_mac_enet_mode) { + case MII_CONTYPE_RGMII: + reg |= IF_MODE_RG; + /* FALLTHROUGH */ + case MII_CONTYPE_GMII: + case MII_CONTYPE_SGMII: + case MII_CONTYPE_QSGMII: + reg |= IF_MODE_IFMODE_GMII; + break; + case MII_CONTYPE_RMII: + reg |= IF_MODE_RG; + /* FALLTHROUGH */ + case MII_CONTYPE_MII: + reg |= IF_MODE_IFMODE_MII; + break; + } + + bus_write_4(sc->sc_base.sc_mem, MEMAC_IF_MODE, reg); + + return (0); +} +/** @} */ + + +/** + * @group IFnet routines. + * @{ + */ +static int +memac_set_mtu(struct memac_softc *sc, unsigned int mtu) +{ + + mtu += ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN + ETHER_CRC_LEN; + + MEMAC_LOCK_ASSERT(sc); + + if (mtu >= MEMAC_MIN_FRAME_SIZE && mtu <= MEMAC_MAX_FRAME_SIZE) { + bus_write_4(sc->sc_base.sc_mem, MEMAC_REG_MAXFRM, mtu); + return (mtu); + } + + return (0); +} + +static u_int +memac_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) +{ + struct memac_softc *sc = arg; + uint8_t *addr = LLADDR(sdl); + uint32_t hash = 0; + uint8_t a, h; + + /* Hash is 6 bits, composed if [XOR{47:40},XOR{39:32},....] */ + for (int i = 0; i < 6; i++) { + a = addr[i]; + h = 0; + for (int j = 0; j < 8; j++, a >>= 1) { + h ^= (a & 0x1); + } + hash |= (h << i); + } + bus_write_4(sc->sc_base.sc_mem, HASHTABLE_CTRL, hash | CTRL_MCAST); + + return (1); +} + +static void +memac_setup_multicast(struct memac_softc *sc) +{ + + if (if_getflags(sc->sc_base.sc_ifnet) & IFF_ALLMULTI) { + for (int i = 0; i < HASHTABLE_SIZE; i++) + bus_write_4(sc->sc_base.sc_mem, + HASHTABLE_CTRL, CTRL_MCAST | i); + } else { + /* Clear the hash table */ + for (int i = 0; i < HASHTABLE_SIZE; i++) + bus_write_4(sc->sc_base.sc_mem, + HASHTABLE_CTRL, i); + } + + if_foreach_llmaddr(sc->sc_base.sc_ifnet, memac_hash_maddr, sc); +} + +static void +memac_setup_promisc(struct memac_softc *sc) +{ + uint32_t reg; + + reg = bus_read_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG); + reg &= ~COMMAND_CONFIG_PROMISC; + + if ((if_getflags(sc->sc_base.sc_ifnet) & IFF_PROMISC) != 0) + bus_write_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG, + reg | COMMAND_CONFIG_PROMISC); +} + +static void +memac_if_graceful_stop(struct memac_softc *sc) +{ + struct resource *regs = sc->sc_base.sc_mem; + uint32_t reg; + + reg = bus_read_4(regs, MEMAC_COMMAND_CONFIG); + reg |= COMMAND_CONFIG_RXSTP; + + bus_write_4(regs, MEMAC_COMMAND_CONFIG, reg); + while ((bus_read_4(regs, MEMAC_IEVENT) & IEVENT_RX_EMPTY) == 0) + ; + reg &= COMMAND_CONFIG_RX_EN; + bus_write_4(regs, MEMAC_COMMAND_CONFIG, reg); + + while ((bus_read_4(regs, MEMAC_IEVENT) & IEVENT_TX_EMPTY) == 0) + ; + bus_write_4(regs, MEMAC_COMMAND_CONFIG, reg & ~COMMAND_CONFIG_TX_EN); +} + +static void +memac_mac_enable(struct memac_softc *sc) +{ + uint32_t reg = bus_read_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG); + + reg |= (COMMAND_CONFIG_RX_EN | COMMAND_CONFIG_TX_EN); + + bus_write_4(sc->sc_base.sc_mem, MEMAC_COMMAND_CONFIG, reg); +} + +static int +memac_if_enable_locked(struct memac_softc *sc) +{ + int error; + + MEMAC_LOCK_ASSERT(sc); + + memac_set_mtu(sc, if_getmtu(sc->sc_base.sc_ifnet)); + memac_mac_enable(sc); + + error = FMAN_PORT_ENABLE(sc->sc_base.sc_rx_port); + if (error != 0) + return (EIO); + + error = FMAN_PORT_ENABLE(sc->sc_base.sc_tx_port); + if (error != 0) + return (EIO); + + bus_write_4(sc->sc_base.sc_mem, MEMAC_IEVENT, 0); + memac_setup_multicast(sc); + memac_setup_promisc(sc); + + if_setdrvflagbits(sc->sc_base.sc_ifnet, IFF_DRV_RUNNING, 0); + + /* Refresh link state */ + memac_miibus_statchg(sc->sc_base.sc_dev); + + return (0); +} + +static int +memac_if_disable_locked(struct memac_softc *sc) +{ + int error; + + MEMAC_LOCK_ASSERT(sc); + + error = FMAN_PORT_DISABLE(sc->sc_base.sc_tx_port); + if (error != 0) + return (EIO); + + memac_if_graceful_stop(sc); + + error = FMAN_PORT_DISABLE(sc->sc_base.sc_rx_port); + if (error != 0) + return (EIO); + + if_setdrvflagbits(sc->sc_base.sc_ifnet, 0, IFF_DRV_RUNNING); + + return (0); +} + +static int +memac_if_ioctl(if_t ifp, u_long command, caddr_t data) +{ + struct memac_softc *sc; + struct ifreq *ifr; + uint32_t changed; + int error; + + sc = if_getsoftc(ifp); + ifr = (struct ifreq *)data; + error = 0; + + /* Basic functionality to achieve media status reports */ + switch (command) { + case SIOCSIFMTU: + MEMAC_LOCK(sc); + if (memac_set_mtu(sc, ifr->ifr_mtu)) + if_setmtu(ifp, ifr->ifr_mtu); + else + error = EINVAL; + MEMAC_UNLOCK(sc); + break; + case SIOCSIFFLAGS: + MEMAC_LOCK(sc); + if (if_getflags(ifp) & IFF_UP) { + if (!(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) + memac_if_init_locked(sc); + } else if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) + error = memac_if_disable_locked(sc); + + MEMAC_UNLOCK(sc); + break; + + case SIOCADDMULTI: + case SIOCDELMULTI: + if (if_getflags(sc->sc_base.sc_ifnet) & IFF_UP) { + MEMAC_LOCK(sc); + memac_setup_multicast(sc); + MEMAC_UNLOCK(sc); + } + break; + + case SIOCSIFCAP: + changed = if_getcapenable(ifp) ^ ifr->ifr_reqcap; + if ((changed & (IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6)) != 0) + if_togglecapenable(ifp, + IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6); + if ((changed & (IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6)) != 0) { + if_togglecapenable(ifp, + IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6); + if_togglehwassist(ifp, DPAA_CSUM_TX_OFFLOAD); + } + break; + + case SIOCGIFMEDIA: + case SIOCSIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &sc->sc_base.sc_mii->mii_media, + command); + break; + + default: + error = ether_ioctl(ifp, command, data); + } + + return (error); +} + +static void +memac_if_tick(void *arg) +{ + struct memac_softc *sc; + + sc = arg; + + /* TODO */ + MEMAC_LOCK(sc); + + mii_tick(sc->sc_base.sc_mii); + callout_reset(&sc->sc_base.sc_tick_callout, hz, memac_if_tick, sc); + + MEMAC_UNLOCK(sc); +} + +static void +memac_if_deinit_locked(struct memac_softc *sc) +{ + + MEMAC_LOCK_ASSERT(sc); + + MEMAC_UNLOCK(sc); + callout_drain(&sc->sc_base.sc_tick_callout); + MEMAC_LOCK(sc); +} + +static void +memac_if_set_macaddr(struct memac_softc *sc, const char *addr) +{ + uint32_t reg; + + reg = (addr[3] << 24) | (addr[2] << 16) | (addr[1] << 8) | addr[0]; + bus_write_4(sc->sc_base.sc_mem, MEMAC_MAC_ADDR_0, reg); + reg = (addr[5] << 8) | (addr[4]); + bus_write_4(sc->sc_base.sc_mem, MEMAC_MAC_ADDR_1, reg); +} + +static void +memac_if_init_locked(struct memac_softc *sc) +{ + int error; + const char *macaddr; + + MEMAC_LOCK_ASSERT(sc); + + macaddr = if_getlladdr(sc->sc_base.sc_ifnet); + memac_if_set_macaddr(sc, macaddr); + + /* Start MII polling */ + if (sc->sc_base.sc_mii) + callout_reset(&sc->sc_base.sc_tick_callout, hz, + memac_if_tick, sc); + + if (if_getflags(sc->sc_base.sc_ifnet) & IFF_UP) { + error = memac_if_enable_locked(sc); + if (error != 0) + goto err; + } else { + error = memac_if_disable_locked(sc); + if (error != 0) + goto err; + } + + if_link_state_change(sc->sc_base.sc_ifnet, LINK_STATE_UP); + + bus_write_4(sc->sc_base.sc_mem, MEMAC_CL01_PAUSE_QUANTA, + DEFAULT_PAUSE_QUANTA); + + return; + +err: + memac_if_deinit_locked(sc); + device_printf(sc->sc_base.sc_dev, "initialization error.\n"); + return; +} + +static void +memac_if_init(void *data) +{ + struct memac_softc *sc; + + sc = data; + + MEMAC_LOCK(sc); + memac_if_init_locked(sc); + MEMAC_UNLOCK(sc); +} + +static void +memac_if_start(if_t ifp) +{ + struct memac_softc *sc; + + sc = if_getsoftc(ifp); + MEMAC_LOCK(sc); + dpaa_eth_if_start_locked(&sc->sc_base); + MEMAC_UNLOCK(sc); +} + +static void +memac_if_watchdog(if_t ifp) +{ + /* TODO */ +} +/** @} */ + + +/** + * @group IFmedia routines. + * @{ + */ +static int +memac_ifmedia_upd(if_t ifp) +{ + struct memac_softc *sc = if_getsoftc(ifp); + + return (0); + MEMAC_LOCK(sc); + mii_mediachg(sc->sc_base.sc_mii); + MEMAC_UNLOCK(sc); + + return (0); +} + +static void +memac_ifmedia_fixed_sts(if_t ifp, struct ifmediareq *ifmr) +{ + struct memac_softc *sc = if_getsoftc(ifp); + + MEMAC_LOCK(sc); + ifmr->ifm_count = 1; + ifmr->ifm_mask = 0; + ifmr->ifm_status = IFM_AVALID | IFM_ACTIVE; + ifmr->ifm_current = ifmr->ifm_active = + sc->sc_base.sc_mii->mii_media.ifm_cur->ifm_media; + ifmr->ifm_active = ifmr->ifm_current; + + /* + * In non-PHY usecases, we need to signal link state up, otherwise + * certain things requiring a link event (e.g async DHCP client) from + * devd do not happen. + */ + if (if_getlinkstate(ifp) == LINK_STATE_UNKNOWN) { + if_link_state_change(ifp, LINK_STATE_UP); + } + + /* We assume the link is static, as in a peer switch. */ + + MEMAC_UNLOCK(sc); + + return; +} + +static void +memac_ifmedia_sts(if_t ifp, struct ifmediareq *ifmr) +{ + struct memac_softc *sc = if_getsoftc(ifp); + + MEMAC_LOCK(sc); + + mii_pollstat(sc->sc_base.sc_mii); + + ifmr->ifm_active = sc->sc_base.sc_mii->mii_media_active; + ifmr->ifm_status = sc->sc_base.sc_mii->mii_media_status; + + MEMAC_UNLOCK(sc); +} +/** @} */ + + +/** + * @group dTSEC bus interface. + * @{ + */ + +int +memac_attach(device_t dev) +{ + struct memac_softc *sc; + int error; + if_t ifp; + + sc = device_get_softc(dev); + + sc->sc_base.sc_dev = dev; + + /* Init locks */ + mtx_init(&sc->sc_base.sc_lock, device_get_nameunit(dev), + "mEMAC Global Lock", MTX_DEF); + + mtx_init(&sc->sc_base.sc_mii_lock, device_get_nameunit(dev), + "mEMAC MII Lock", MTX_DEF); + + /* Init callouts */ + callout_init(&sc->sc_base.sc_tick_callout, CALLOUT_MPSAFE); + + /* Create RX buffer pool */ + error = dpaa_eth_pool_rx_init(&sc->sc_base); + if (error != 0) + return (EIO); + + /* Create RX frame queue range */ + error = dpaa_eth_fq_rx_init(&sc->sc_base); + if (error != 0) + return (EIO); + + /* Create frame info pool */ + error = dpaa_eth_fi_pool_init(&sc->sc_base); + if (error != 0) + return (EIO); + + /* Create TX frame queue range */ + error = dpaa_eth_fq_tx_init(&sc->sc_base); + if (error != 0) + return (EIO); + + /* Init FMan MAC module. */ + error = memac_fm_mac_init(sc, sc->sc_base.sc_mac_addr); + if (error != 0) { + memac_detach(dev); + return (ENXIO); + } + + dpaa_eth_fm_port_rx_init(&sc->sc_base); + dpaa_eth_fm_port_tx_init(&sc->sc_base); + + /* Create network interface for upper layers */ + ifp = sc->sc_base.sc_ifnet = if_alloc(IFT_ETHER); + if_setsoftc(ifp, sc); + + if_setflags(ifp, IFF_SIMPLEX | IFF_BROADCAST | IFF_MULTICAST); + if_setinitfn(ifp, memac_if_init); + if_setstartfn(ifp, memac_if_start); + if_setioctlfn(ifp, memac_if_ioctl); + if_setsendqlen(ifp, IFQ_MAXLEN); + if_setsendqready(ifp); + + if (sc->sc_base.sc_phy_addr >= 0) + if_initname(ifp, device_get_name(sc->sc_base.sc_dev), + device_get_unit(sc->sc_base.sc_dev)); + else + if_initname(ifp, "memac_phy", + device_get_unit(sc->sc_base.sc_dev)); + + + if_setcapabilities(ifp, IFCAP_JUMBO_MTU | + IFCAP_VLAN_MTU | IFCAP_VLAN_HWCSUM | + IFCAP_RXCSUM | IFCAP_RXCSUM_IPV6 | + IFCAP_TXCSUM | IFCAP_TXCSUM_IPV6); + if_setcapenable(ifp, if_getcapabilities(ifp)); + if_sethwassist(ifp, DPAA_CSUM_TX_OFFLOAD); + + /* Attach PHY(s) */ + if (!sc->sc_fixed_link) { + error = mii_attach(sc->sc_base.sc_dev, &sc->sc_base.sc_mii_dev, + ifp, memac_ifmedia_upd, memac_ifmedia_sts, BMSR_DEFCAPMASK, + sc->sc_base.sc_phy_addr, MII_OFFSET_ANY, 0); + if (error) { + device_printf(sc->sc_base.sc_dev, + "attaching PHYs failed: %d\n", error); + memac_detach(sc->sc_base.sc_dev); + return (error); + } + sc->sc_base.sc_mii = device_get_softc(sc->sc_base.sc_mii_dev); + } else { + phandle_t node; + uint32_t type = IFM_ETHER; + uint32_t speed; + + node = ofw_bus_find_child(ofw_bus_get_node(dev), "fixed-link"); + if (OF_getencprop(node, "speed", &speed, sizeof(speed)) <= 0) { + device_printf(dev, + "fixed link has no speed property\n"); + memac_detach(sc->sc_base.sc_dev); + return (ENXIO); + } + switch (speed) { + case 10: + type |= IFM_10_T; + break; + case 100: + type |= IFM_100_TX; + break; + case 1000: + type |= IFM_1000_T; + break; + case 2500: + type |= IFM_2500_T; + break; + case 5000: + type |= IFM_5000_T; + break; + case 10000: + type |= IFM_10G_T; + break; + } + if (OF_hasprop(node, "full-duplex")) + type |= IFM_FDX; + sc->sc_base.sc_mii = malloc(sizeof(*sc->sc_base.sc_mii), + M_DEVBUF, M_WAITOK | M_ZERO); + ifmedia_init(&sc->sc_base.sc_mii->mii_media, 0, + memac_ifmedia_upd, memac_ifmedia_fixed_sts); + ifmedia_add(&sc->sc_base.sc_mii->mii_media, type, 0, NULL); + ifmedia_set(&sc->sc_base.sc_mii->mii_media, type); + } + + /* Attach to stack */ + ether_ifattach(ifp, sc->sc_base.sc_mac_addr); + + return (0); +} + +int +memac_detach(device_t dev) +{ + struct memac_softc *sc; + if_t ifp; + + sc = device_get_softc(dev); + ifp = sc->sc_base.sc_ifnet; + + if (device_is_attached(dev)) { + ether_ifdetach(ifp); + /* Shutdown interface */ + MEMAC_LOCK(sc); + memac_if_deinit_locked(sc); + MEMAC_UNLOCK(sc); + } + + if (sc->sc_base.sc_ifnet) { + if_free(sc->sc_base.sc_ifnet); + sc->sc_base.sc_ifnet = NULL; + } + + /* Free RX/TX FQRs */ + dpaa_eth_fq_rx_free(&sc->sc_base); + dpaa_eth_fq_tx_free(&sc->sc_base); + + /* Free frame info pool */ + dpaa_eth_fi_pool_free(&sc->sc_base); + + /* Free RX buffer pool */ + dpaa_eth_pool_rx_free(&sc->sc_base); + + /* Destroy lock */ + mtx_destroy(&sc->sc_base.sc_lock); + + return (0); +} + +int +memac_suspend(device_t dev) +{ + + return (0); +} + +int +memac_resume(device_t dev) +{ + + return (0); +} + +int +memac_shutdown(device_t dev) +{ + + return (0); +} +/** @} */ + + +/** + * @group MII bus interface. + * @{ + */ +int +memac_miibus_readreg(device_t dev, int phy, int reg) +{ + struct memac_softc *sc; + + sc = device_get_softc(dev); + + return (MIIBUS_READREG(sc->sc_base.sc_mdio, phy, reg)); +} + +int +memac_miibus_writereg(device_t dev, int phy, int reg, int value) +{ + + struct memac_softc *sc; + + sc = device_get_softc(dev); + + return (MIIBUS_WRITEREG(sc->sc_base.sc_mdio, phy, reg, value)); +} + +void +memac_miibus_statchg(device_t dev) +{ + struct memac_softc *sc; + uint32_t reg; + bool duplex; + int speed; + + sc = device_get_softc(dev); + + MEMAC_LOCK_ASSERT(sc); + + duplex = ((sc->sc_base.sc_mii->mii_media_active & IFM_GMASK) == IFM_FDX); + + switch (IFM_SUBTYPE(sc->sc_base.sc_mii->mii_media_active)) { + case IFM_AUTO: + speed = IF_MODE_ENA; + break; + case IFM_1000_T: + case IFM_1000_SX: + if (!duplex) { + device_printf(sc->sc_base.sc_dev, + "Only full-duplex supported for 1Gbps speeds"); + return; + } + speed = IF_MODE_SSP_1GB; + break; + + case IFM_100_TX: + speed = IF_MODE_SSP_100MB; + break; + default: + speed = IF_MODE_SSP_10MB; + break; + } + + reg = bus_read_4(sc->sc_base.sc_mem, MEMAC_IF_MODE); + reg &= ~(IF_MODE_ENA | IF_MODE_SSP_M | IF_MODE_SFD); + reg |= 0x2; + + if (duplex) + reg |= IF_MODE_SFD; + else + reg |= IF_MODE_HD; + reg |= speed; + bus_write_4(sc->sc_base.sc_mem, MEMAC_IF_MODE, reg); +} +/** @} */ diff --git a/sys/dev/dpaa/if_memac.h b/sys/dev/dpaa/if_memac.h new file mode 100644 index 000000000000..98942abaf79c --- /dev/null +++ b/sys/dev/dpaa/if_memac.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2026 Justin Hibbits + * Copyright (c) 2011-2012 Semihalf. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef IF_MEMAC_H_ +#define IF_MEMAC_H_ + +/** + * @group dTSEC common API. + * @{ + */ +#define MEMAC_MODE_REGULAR 0 + +#define MEMAC_LOCK(sc) mtx_lock(&(sc)->sc_base.sc_lock) +#define MEMAC_UNLOCK(sc) mtx_unlock(&(sc)->sc_base.sc_lock) +#define MEMAC_LOCK_ASSERT(sc) mtx_assert(&(sc)->sc_base.sc_lock, MA_OWNED) +#define MEMAC_MII_LOCK(sc) mtx_lock(&(sc)->sc_base.sc_mii_lock) +#define MEMAC_MII_UNLOCK(sc) mtx_unlock(&(sc)->sc_base.sc_mii_lock) + +enum eth_dev_type { + ETH_MEMAC = 0x1, + ETH_10GSEC = 0x2 +}; + +struct memac_softc { + struct dpaa_eth_softc sc_base; + bool sc_fixed_link; +}; +/** @} */ + + +/** + * @group dTSEC bus interface. + * @{ + */ +int memac_attach(device_t dev); +int memac_detach(device_t dev); +int memac_suspend(device_t dev); +int memac_resume(device_t dev); +int memac_shutdown(device_t dev); +int memac_miibus_readreg(device_t dev, int phy, int reg); +int memac_miibus_writereg(device_t dev, int phy, int reg, + int value); +void memac_miibus_statchg(device_t dev); +/** @} */ + +#endif /* IF_MEMAC_H_ */ diff --git a/sys/dev/dpaa/if_memac_fdt.c b/sys/dev/dpaa/if_memac_fdt.c new file mode 100644 index 000000000000..f136608a906c --- /dev/null +++ b/sys/dev/dpaa/if_memac_fdt.c @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2026 Justin Hibbits + * Copyright (c) 2012 Semihalf. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/kernel.h> +#include <sys/module.h> +#include <sys/rman.h> +#include <sys/socket.h> + +#include <machine/bus.h> + +#include <powerpc/mpc85xx/mpc85xx.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> +#include <dev/mii/mii_fdt.h> + +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> +#include <dev/ofw/openfirm.h> + +#include "miibus_if.h" + +#include "dpaa_eth.h" +#include "if_memac.h" +#include "fman.h" + + +static int memac_fdt_probe(device_t dev); +static int memac_fdt_attach(device_t dev); + +static device_method_t memac_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, memac_fdt_probe), + DEVMETHOD(device_attach, memac_fdt_attach), + DEVMETHOD(device_detach, memac_detach), + + DEVMETHOD(device_shutdown, memac_shutdown), + DEVMETHOD(device_suspend, memac_suspend), + DEVMETHOD(device_resume, memac_resume), + + /* Bus interface */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + DEVMETHOD(bus_driver_added, bus_generic_driver_added), + + /* MII interface */ + DEVMETHOD(miibus_readreg, memac_miibus_readreg), + DEVMETHOD(miibus_writereg, memac_miibus_writereg), + DEVMETHOD(miibus_statchg, memac_miibus_statchg), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(memac, memac_driver, memac_methods, sizeof(struct memac_softc)); + +DRIVER_MODULE(memac, fman, memac_driver, 0, 0); +DRIVER_MODULE(miibus, memac, miibus_driver, 0, 0); +MODULE_DEPEND(memac, ether, 1, 1, 1); +MODULE_DEPEND(memac, miibus, 1, 1, 1); + +static int +memac_fdt_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "fsl,fman-memac")) + return (ENXIO); + + device_set_desc(dev, + "Freescale Multirate Ethernet Media Access Controller"); + + return (BUS_PROBE_DEFAULT); +} + +static int +memac_fdt_attach(device_t dev) +{ + struct memac_softc *sc; + device_t phy_dev; + phandle_t enet_node, phy_node; + phandle_t fman_rxtx_node[2]; + pcell_t fman_tx_cell, mac_id; + + sc = device_get_softc(dev); + enet_node = ofw_bus_get_node(dev); + + if (OF_getprop(enet_node, "local-mac-address", + (void *)sc->sc_base.sc_mac_addr, 6) == -1) { + device_printf(dev, + "Could not load local-mac-addr property from DTS\n"); + return (ENXIO); + } + + /* Get PHY connection type */ + sc->sc_base.sc_mac_enet_mode = mii_fdt_get_contype(enet_node); + + sc->sc_fixed_link = OF_hasprop(enet_node, "fixed-link") || + (ofw_bus_find_child(enet_node, "fixed-link") != 0); + if (!sc->sc_fixed_link) { + OF_getprop(enet_node, "phy-handle", &phy_node, sizeof(phy_node)); + phy_node = OF_node_from_xref(phy_node); + + if (OF_getencprop(phy_node, "reg", (void *)&sc->sc_base.sc_phy_addr, + sizeof(sc->sc_base.sc_phy_addr)) <= 0) + return (ENXIO); + + phy_dev = OF_device_from_xref(OF_xref_from_node(OF_parent(phy_node))); + + if (phy_dev == NULL) { + device_printf(dev, "No PHY found.\n"); + return (ENXIO); + } + + sc->sc_base.sc_mdio = phy_dev; + } + + /* Get MAC memory offset in SoC */ + sc->sc_base.sc_mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 0, RF_ACTIVE); + if (sc->sc_base.sc_mem == NULL) + return (ENXIO); + + sc->sc_base.sc_mac_enet_mode = mii_fdt_get_contype(enet_node); + + if (sc->sc_base.sc_mac_enet_mode == MII_CONTYPE_UNKNOWN) { + device_printf(dev, "unknown MII type, defaulting to SGMII\n"); + sc->sc_base.sc_mac_enet_mode = MII_CONTYPE_SGMII; + } + + if (OF_getencprop(enet_node, "cell-index", + (void *)&mac_id, sizeof(mac_id)) <= 0) + return (ENXIO); + sc->sc_base.sc_eth_id = mac_id; + + /* Get RX/TX port handles */ + if (OF_getencprop(enet_node, "fsl,fman-ports", (void *)fman_rxtx_node, + sizeof(fman_rxtx_node)) <= 0) + return (ENXIO); + + if (fman_rxtx_node[0] == 0) + return (ENXIO); + + if (fman_rxtx_node[1] == 0) + return (ENXIO); + + sc->sc_base.sc_rx_port = OF_device_from_xref(fman_rxtx_node[0]); + sc->sc_base.sc_tx_port = OF_device_from_xref(fman_rxtx_node[1]); + + if (sc->sc_base.sc_rx_port == NULL || sc->sc_base.sc_tx_port == NULL) + return (ENXIO); + + fman_rxtx_node[1] = OF_node_from_xref(fman_rxtx_node[1]); + if (OF_getencprop(fman_rxtx_node[1], "cell-index", &fman_tx_cell, + sizeof(fman_tx_cell)) <= 0) + return (ENXIO); + /* Get QMan channel */ + sc->sc_base.sc_port_tx_qman_chan = fman_qman_channel_id(device_get_parent(dev), + fman_tx_cell); + + return (memac_attach(dev)); +} diff --git a/sys/dev/dpaa/portals.h b/sys/dev/dpaa/portals.h index a2d6294f3d8e..ef550b09a726 100644 --- a/sys/dev/dpaa/portals.h +++ b/sys/dev/dpaa/portals.h @@ -24,39 +24,30 @@ * SUCH DAMAGE. */ -typedef struct dpaa_portal { - int dp_irid; /* interrupt rid */ - struct resource *dp_ires; /* interrupt resource */ +#ifndef DPAA_PORTALS_H +#define DPAA_PORTALS_H - bool dp_regs_mapped; /* register mapping status */ - - t_Handle dp_ph; /* portal's handle */ - vm_paddr_t dp_ce_pa; /* portal's CE area PA */ - vm_paddr_t dp_ci_pa; /* portal's CI area PA */ - uint32_t dp_ce_size; /* portal's CE area size */ - uint32_t dp_ci_size; /* portal's CI area size */ - uintptr_t dp_intr_num; /* portal's intr. number */ -} dpaa_portal_t; - -struct dpaa_portals_softc { +struct dpaa_portal_softc { device_t sc_dev; /* device handle */ - vm_paddr_t sc_dp_pa; /* portal's PA */ - uint32_t sc_dp_size; /* portal's size */ - int sc_rrid[2]; /* memory rid */ - struct resource *sc_rres[2]; /* memory resource */ - dpaa_portal_t sc_dp[MAXCPU]; -}; - -struct dpaa_portals_devinfo { - struct resource_list di_res; - int di_intr_rid; + vm_paddr_t sc_ce_pa; /* portal's CE PA */ + vm_offset_t sc_ce_va; + vm_paddr_t sc_ci_pa; /* portal's CI PA */ + vm_offset_t sc_ci_va; + int sc_cpu; + uint32_t sc_ce_size; /* portal's CE size */ + uint32_t sc_ci_size; /* portal's CI size */ + struct resource *sc_mres[2]; /* memory resource */ + struct resource *sc_ires; /* Interrupt */ + void *sc_intr_cookie; + bool sc_regs_mapped; /* register mapping status */ }; -int bman_portals_attach(device_t); -int bman_portals_detach(device_t); +int bman_portal_attach(device_t, int); +int bman_portal_detach(device_t); -int qman_portals_attach(device_t); -int qman_portals_detach(device_t); +int qman_portal_attach(device_t, int); +int qman_portal_detach(device_t); -int dpaa_portal_alloc_res(device_t, struct dpaa_portals_devinfo *, int); -void dpaa_portal_map_registers(struct dpaa_portals_softc *); +int dpaa_portal_alloc_res(device_t, int); +void dpaa_portal_map_registers(struct dpaa_portal_softc *); +#endif diff --git a/sys/dev/dpaa/portals_common.c b/sys/dev/dpaa/portals_common.c index ed8e577694f2..c4501af05889 100644 --- a/sys/dev/dpaa/portals_common.c +++ b/sys/dev/dpaa/portals_common.c @@ -41,127 +41,46 @@ #include <machine/resource.h> #include <machine/tlb.h> -#include <contrib/ncsw/inc/error_ext.h> -#include <contrib/ncsw/inc/xx_ext.h> - #include "portals.h" int -dpaa_portal_alloc_res(device_t dev, struct dpaa_portals_devinfo *di, int cpu) +dpaa_portal_alloc_res(device_t dev, int cpu) { - struct dpaa_portals_softc *sc = device_get_softc(dev); - struct resource_list_entry *rle; - int err; - struct resource_list *res; + struct dpaa_portal_softc *sc = device_get_softc(dev); - /* Check if MallocSmart allocator is ready */ - if (XX_MallocSmartInit() != E_OK) + sc->sc_mres[0] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + 0, RF_ACTIVE); + if (sc->sc_mres[0] == NULL) { + device_printf(dev, + "Could not allocate cache enabled memory.\n"); return (ENXIO); - - res = &di->di_res; - - /* - * Allocate memory. - * Reserve only one pair of CE/CI virtual memory regions - * for all CPUs, in order to save the space. - */ - if (sc->sc_rres[0] == NULL) { - /* Cache enabled area */ - rle = resource_list_find(res, SYS_RES_MEMORY, 0); - sc->sc_rrid[0] = 0; - sc->sc_rres[0] = bus_alloc_resource(dev, - SYS_RES_MEMORY, &sc->sc_rrid[0], rle->start + sc->sc_dp_pa, - rle->end + sc->sc_dp_pa, rle->count, RF_ACTIVE); - if (sc->sc_rres[0] == NULL) { - device_printf(dev, - "Could not allocate cache enabled memory.\n"); - return (ENXIO); - } - tlb1_set_entry(rman_get_bushandle(sc->sc_rres[0]), - rle->start + sc->sc_dp_pa, rle->count, _TLB_ENTRY_MEM); - /* Cache inhibited area */ - rle = resource_list_find(res, SYS_RES_MEMORY, 1); - sc->sc_rrid[1] = 1; - sc->sc_rres[1] = bus_alloc_resource(dev, - SYS_RES_MEMORY, &sc->sc_rrid[1], rle->start + sc->sc_dp_pa, - rle->end + sc->sc_dp_pa, rle->count, RF_ACTIVE); - if (sc->sc_rres[1] == NULL) { - device_printf(dev, - "Could not allocate cache inhibited memory.\n"); - bus_release_resource(dev, SYS_RES_MEMORY, - sc->sc_rrid[0], sc->sc_rres[0]); - return (ENXIO); - } - tlb1_set_entry(rman_get_bushandle(sc->sc_rres[1]), - rle->start + sc->sc_dp_pa, rle->count, _TLB_ENTRY_IO); - sc->sc_dp[cpu].dp_regs_mapped = 1; } - /* Acquire portal's CE_PA and CI_PA */ - rle = resource_list_find(res, SYS_RES_MEMORY, 0); - sc->sc_dp[cpu].dp_ce_pa = rle->start + sc->sc_dp_pa; - sc->sc_dp[cpu].dp_ce_size = rle->count; - rle = resource_list_find(res, SYS_RES_MEMORY, 1); - sc->sc_dp[cpu].dp_ci_pa = rle->start + sc->sc_dp_pa; - sc->sc_dp[cpu].dp_ci_size = rle->count; - - /* Allocate interrupts */ - rle = resource_list_find(res, SYS_RES_IRQ, 0); - sc->sc_dp[cpu].dp_irid = 0; - sc->sc_dp[cpu].dp_ires = bus_alloc_resource(dev, - SYS_RES_IRQ, &sc->sc_dp[cpu].dp_irid, rle->start, rle->end, - rle->count, RF_ACTIVE); - /* Save interrupt number for later use */ - sc->sc_dp[cpu].dp_intr_num = rle->start; - - if (sc->sc_dp[cpu].dp_ires == NULL) { - device_printf(dev, "Could not allocate irq.\n"); + /* Cache inhibited area */ + sc->sc_mres[1] = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + 1, RF_ACTIVE); + if (sc->sc_mres[1] == NULL) { + device_printf(dev, + "Could not allocate cache inhibited memory.\n"); + bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mres[0]); return (ENXIO); } - err = XX_PreallocAndBindIntr(dev, (uintptr_t)sc->sc_dp[cpu].dp_ires, cpu); + sc->sc_dev = dev; + sc->sc_ce_va = rman_get_bushandle(sc->sc_mres[0]); + sc->sc_ce_size = rman_get_size(sc->sc_mres[0]); + sc->sc_ce_pa = pmap_kextract(sc->sc_ce_va); + sc->sc_ci_va = rman_get_bushandle(sc->sc_mres[1]); + sc->sc_ci_size = rman_get_size(sc->sc_mres[1]); + sc->sc_ci_pa = pmap_kextract(sc->sc_ci_va); + tlb1_set_entry(sc->sc_ce_va, sc->sc_ce_pa, sc->sc_ce_size, + _TLB_ENTRY_MEM | _TLB_ENTRY_SHARED); + sc->sc_ires = bus_alloc_resource_any(dev, SYS_RES_IRQ, 0, RF_ACTIVE); - if (err != E_OK) { - device_printf(dev, "Could not prealloc and bind interrupt\n"); - bus_release_resource(dev, SYS_RES_IRQ, - sc->sc_dp[cpu].dp_irid, sc->sc_dp[cpu].dp_ires); - sc->sc_dp[cpu].dp_ires = NULL; + /* Allocate interrupts */ + if (sc->sc_ires == NULL) { + device_printf(dev, "Could not allocate irq.\n"); return (ENXIO); } -#if 0 - err = bus_generic_config_intr(dev, rle->start, di->di_intr_trig, - di->di_intr_pol); - if (err != 0) { - device_printf(dev, "Could not configure interrupt\n"); - bus_release_resource(dev, SYS_RES_IRQ, - sc->sc_dp[cpu].dp_irid, sc->sc_dp[cpu].dp_ires); - sc->sc_dp[cpu].dp_ires = NULL; - return (err); - } -#endif - return (0); } - -void -dpaa_portal_map_registers(struct dpaa_portals_softc *sc) -{ - unsigned int cpu; - - sched_pin(); - cpu = PCPU_GET(cpuid); - if (sc->sc_dp[cpu].dp_regs_mapped) - goto out; - - tlb1_set_entry(rman_get_bushandle(sc->sc_rres[0]), - sc->sc_dp[cpu].dp_ce_pa, sc->sc_dp[cpu].dp_ce_size, - _TLB_ENTRY_MEM); - tlb1_set_entry(rman_get_bushandle(sc->sc_rres[1]), - sc->sc_dp[cpu].dp_ci_pa, sc->sc_dp[cpu].dp_ci_size, - _TLB_ENTRY_IO); - - sc->sc_dp[cpu].dp_regs_mapped = 1; - -out: - sched_unpin(); -} diff --git a/sys/dev/dpaa/qman.c b/sys/dev/dpaa/qman.c index fccaa853918b..9143ebde5cb4 100644 --- a/sys/dev/dpaa/qman.c +++ b/sys/dev/dpaa/qman.c @@ -1,3 +1,8 @@ +/* + * Copyright (c) 2026 Justin Hibbits + * + * SPDX-License-Identifier: BSD-2-Clause + */ /*- * Copyright (c) 2011-2012 Semihalf. * All rights reserved. @@ -29,6 +34,7 @@ #include <sys/kernel.h> #include <sys/bus.h> #include <sys/lock.h> +#include <sys/malloc.h> #include <sys/module.h> #include <sys/mutex.h> #include <sys/proc.h> @@ -41,139 +47,276 @@ #include <machine/resource.h> #include <machine/tlb.h> -#include "qman.h" +#include "dpaa_common.h" #include "portals.h" +#include "qman.h" +#include "qman_var.h" +#include "qman_portal_if.h" + +/* Registers */ +#define QCSP_IO_CFG(n) (0x004 + (n) * 16) +#define IO_CFG_SDEST_M 0x00ff0000 +#define IO_CFG_SDEST_S 16 +#define QMAN_DCP_CFG(n) (0x300 + (n) * 0x10) +#define DCP_CFG_ED 0x00000100 +#define DCP_CFG_ED_3 0x00001000 +#define QMAN_PFDR_FP_LWIT 0x410 +#define QMAN_PFDR_CFG 0x414 +#define QMAN_SFDR_CFG 0x500 +#define QMAN_MCR 0xb00 +#define MCR_INIT_PFDR 0x01000000 +#define MCR_READ_PFDR 0x02000000 +#define MCR_READ_SFDR 0x03000000 +#define MCR_QUERY_FQD_FILL 0x10000000 +#define MCR_QUERY_FQD_TAGS 0x11000000 +#define MCR_QUERY_FQD_CACHE 0x12000000 +#define MCR_QUERY_WQ 0x20000000 +#define MCR_RSLT_OK 0xf0000000 +#define MCR_RSLT_OK_DATA 0xf1000000 +#define MCR_RSLT_ABRT_INV 0xf4000000 +#define MCR_RSLT_ABRT_DIS 0xf8000000 +#define MCR_RSLT_ABRT_IDX 0xff000000 +#define MCR_RSLT_ABRT_MASK 0xff000000 +#define QMAN_MCP0 0xb04 +#define QMAN_MCP1 0xb08 +#define QMAN_IP_REV_1 0xbf8 +#define IP_MJ_M 0x0000ff00 +#define IP_MJ_S 8 +#define IP_MN_M 0x000000ff +#define QMAN_FQD_BARE 0xc00 +#define QMAN_FQD_BAR 0xc04 +#define QMAN_FQD_AR 0xc10 +#define AR_EN 0x80000000 +#define QMAN_PFDR_BARE 0xc20 +#define QMAN_PFDR_BAR 0xc24 +#define QMAN_PFDR_AR 0xc30 +#define QMAN_QCSP_BARE 0xc80 +#define QMAN_QCSP_BAR 0xc84 +#define QMAN_QCSP_AR 0xc90 +#define QMAN_CI_SCHED_CFG 0xd00 +#define CI_SCHED_CFG_SW 0x80000000 +#define CI_SCHED_CFG_SRCCIV 0x04000000 /* Recommended */ +#define CI_SCHED_CFG_SRQ_W_M 0x00000700 +#define CI_SCHED_CFG_SRQ_W_S 8 +#define CI_SCHED_CFG_RW_W_M 0x00000070 +#define CI_SCHED_CFG_RW_W_S 4 +#define CI_SCHED_CFG_BMAN_W_M 0x00000007 +#define QMAN_ERR_ISR 0xe00 +#define QMAN_ERR_IER 0xe04 +#define QCSP_IO_CFG_3(n) (0x1004 + (n) * 16) + +/* Software portals. Cache-inhibited registers */ + +#define QCSP_DQRR_PDQCR 0x05c + +/* Software portals. Cache-enabled registers */ + +#define QCSP_VERB_INIT_FQ_PARK 0x40 +#define QCSP_VERB_INIT_FQ_SCHED 0x41 +#define QCSP_VERB_QUERY_FQ 0x44 +#define QCSP_VERB_QUERY_FQ_NP 0x45 +#define QCSP_VERB_ALTER_FQ_SCHED 0x48 +#define QCSP_VERB_ALTER_FQ_FE 0x49 +#define QCSP_VERB_ALTER_FQ_RETIRE 0x4a +#define QCSP_VERB_ALTER_FQ_TAKE_OUT 0x4b +#define QCSP_VERB_ALTER_FQ_RETIRE_CTXB 0x4c +#define QCSP_VERB_ALTER_FQ_XON 0x4d +#define QCSP_VERB_ALTER_FQ_XOFF 0x4e + +/* Init FQ */ +#define QCSP_INIT_FQ_WE_OAC 0x0100 +#define QCSP_INIT_FQ_WE_ORPC 0x0080 +#define QCSP_INIT_FQ_WE_CGID 0x0040 +#define QCSP_INIT_FQ_WE_FQ_CTRL 0x0020 +#define QCSP_INIT_FQ_WE_DEST_WQ 0x0010 +#define QCSP_INIT_FQ_WE_ICS_CRED 0x0008 +#define QCSP_INIT_FQ_WE_TD_THRESH 0x0004 +#define QCSP_INIT_FQ_WE_CONTEXT_B 0x0002 +#define QCSP_INIT_FQ_WE_CONTEXT_A 0x0001 + +#define QMAN_MC_RES_OK 0xf0 + +#define QMAN_MC_AFQS_NE 0x01 + +/* Init FQ options */ +#define QM_FQCTRL_CGE 0x0400 +#define QM_FQCTRL_TDE 0x0200 +#define QM_FQCTRL_ORP 0x0100 +#define QM_FQCTRL_CTXASTASH 0x0080 +#define QM_FQCTRL_CPCSTASH 0x0040 +#define QM_FQCTRL_FORCESFDR 0x0008 +#define QM_FQCTRL_AVOIDBLOCK 0x0004 +#define QM_FQCTRL_HOLDACTIVE 0x0002 +#define QM_FQCTRL_LIC 0x0001 + +#define QMAN_CHANNEL_POOL1_REV1 0x21 +#define QMAN_CHANNEL_POOL1_REV3 0x401 + +#define QMAN_PFDR_MAX 0xfffeff + +/* P1023 has only 3 pool channels, but we don't support that SoC. */ +#define QMAN_POOL_CHANNELS 15 + +/* P1023 only supports 64 congestion groups... */ +#define QMAN_CGRS 256 -extern struct dpaa_portals_softc *qp_sc; static struct qman_softc *qman_sc; -extern t_Handle qman_portal_setup(struct qman_softc *qsc); +static MALLOC_DEFINE(M_QMAN, "qman", "DPAA Queue Manager structures"); + +int qman_channel_base; +int qman_total_fqids; +struct qman_fq **qman_fq_list; + +/* Entries sorted right-to-left in bit order of the ISR */ +static const char * const qman_errors[] = { + "Invalid enqueue queue", + "Invalid enqueue channel!", + "Invalid enqueue state", + "Invalid enqueue overflow", + "Invalid enqueue configuration", + NULL, + NULL, + NULL, + "Invalid dequeue queue", + "Invalid dequeue source", + "Invalid dequeue FQ", + "Invalid dequeue direct connect portal", + NULL, + NULL, + NULL, + NULL, + "Invalid command verb", + "Invalid FQ flow control state", + NULL, + NULL, + NULL, + NULL, + NULL, + "Insufficient free PFDRs", + "Single-bit ECC error", + "Multi-bit ECC error", + "PFDR low watermark", + "Invalid target transaction", + "Initiator data error", + NULL, + NULL +}; static void -qman_exception(t_Handle app, e_QmExceptions exception) +qman_isr(void *arg) { - struct qman_softc *sc; - const char *message; + struct qman_softc *sc = arg; + uint32_t ier, isr, isr_bit; + int i; - sc = app; + ier = bus_read_4(sc->sc_rres, QMAN_ERR_IER); + isr = bus_read_4(sc->sc_rres, QMAN_ERR_ISR); - switch (exception) { - case e_QM_EX_CORENET_INITIATOR_DATA: - message = "Initiator Data Error"; - break; - case e_QM_EX_CORENET_TARGET_DATA: - message = "CoreNet Target Data Error"; - break; - case e_QM_EX_CORENET_INVALID_TARGET_TRANSACTION: - message = "Invalid Target Transaction"; - break; - case e_QM_EX_PFDR_THRESHOLD: - message = "PFDR Low Watermark Interrupt"; - break; - case e_QM_EX_PFDR_ENQUEUE_BLOCKED: - message = "PFDR Enqueues Blocked Interrupt"; - break; - case e_QM_EX_SINGLE_ECC: - message = "Single Bit ECC Error Interrupt"; - break; - case e_QM_EX_MULTI_ECC: - message = "Multi Bit ECC Error Interrupt"; - break; - case e_QM_EX_INVALID_COMMAND: - message = "Invalid Command Verb Interrupt"; - break; - case e_QM_EX_DEQUEUE_DCP: - message = "Invalid Dequeue Direct Connect Portal Interrupt"; - break; - case e_QM_EX_DEQUEUE_FQ: - message = "Invalid Dequeue FQ Interrupt"; - break; - case e_QM_EX_DEQUEUE_SOURCE: - message = "Invalid Dequeue Source Interrupt"; - break; - case e_QM_EX_DEQUEUE_QUEUE: - message = "Invalid Dequeue Queue Interrupt"; - break; - case e_QM_EX_ENQUEUE_OVERFLOW: - message = "Invalid Enqueue Overflow Interrupt"; - break; - case e_QM_EX_ENQUEUE_STATE: - message = "Invalid Enqueue State Interrupt"; - break; - case e_QM_EX_ENQUEUE_CHANNEL: - message = "Invalid Enqueue Channel Interrupt"; - break; - case e_QM_EX_ENQUEUE_QUEUE: - message = "Invalid Enqueue Queue Interrupt"; - break; - case e_QM_EX_CG_STATE_CHANGE: - message = "CG change state notification"; - break; - default: - message = "Unknown error"; + if ((ier & isr) == 0) + return; + + isr_bit = (isr & ier); + for (i = 0; isr_bit != 0; i++, isr_bit >>= 1) { + if (isr_bit & 1) + device_printf(sc->sc_dev, "%s", qman_errors[i]); } - device_printf(sc->sc_dev, "QMan Exception: %s.\n", message); + bus_write_4(sc->sc_rres, QMAN_ERR_ISR, isr); } -/** - * General received frame callback. - * This is called, when user did not register his own callback for a given - * frame queue range (fqr). - */ -e_RxStoreResponse -qman_received_frame_callback(t_Handle app, t_Handle qm_fqr, t_Handle qm_portal, - uint32_t fqid_offset, t_DpaaFD *frame) + +/* Set up reserved memory configuration for PFDR and FQD, per `off`. */ +static int +qman_set_memory(struct qman_softc *sc, vm_paddr_t pa, + vm_size_t size, bus_size_t off) { - struct qman_softc *sc; + uint32_t bar, bare; + vm_paddr_t old_bar; + + /* + * Register offsets: + * 0 - BARE + * 4 - BAR + * 0x10 - AR + */ + bare = bus_read_4(sc->sc_rres, off); + bar = bus_read_4(sc->sc_rres, off + 4); + old_bar = (vm_paddr_t)bare << 32 | bar; - sc = app; + if (old_bar != 0 && old_bar != pa) { + device_printf(sc->sc_dev, "QMan BAR already initialized!\n"); + return (ENOMEM); + } else if (old_bar == pa) + return (EEXIST); - device_printf(sc->sc_dev, "dummy callback for received frame.\n"); - return (e_RX_STORE_RESPONSE_CONTINUE); + /* + * Zero the memory and flush cache through DMAP. QMan accesses the + * memory as non-coherent. + */ + memset((void *)PHYS_TO_DMAP(pa), 0, size); + cpu_flush_dcache((void *)PHYS_TO_DMAP(pa), size); + + bus_write_4(sc->sc_rres, off, pa >> 32); + bus_write_4(sc->sc_rres, off + 4, (uint32_t)pa); + bus_write_4(sc->sc_rres, off + 0x10, AR_EN | (ilog2(size) - 1)); + + return (0); } -/** - * General rejected frame callback. - * This is called, when user did not register his own callback for a given - * frame queue range (fqr). +/* + * Set up PFDR structures. Some things to keep in mind: + * - npfdr is the total number of PFDRs in the private memory. PFDRs are 64 + * bytes in size, so npfdr is (pfdr_sz/64). + * - PFDR 0-7 are reserved, so the base starts at 8, not 0, so we adjust + * internally. + * - The second parameter is the last PFDR, not the number of PFDRs, so needs to + * be adjusted down one more, so subtract 9. */ -e_RxStoreResponse -qman_rejected_frame_callback(t_Handle app, t_Handle qm_fqr, t_Handle qm_portal, - uint32_t fqid_offset, t_DpaaFD *frame, - t_QmRejectedFrameInfo *qm_rejected_frame_info) +static int +qman_setup_pfdr(struct qman_softc *sc, int npfdr) { - struct qman_softc *sc; + uint32_t res; + + npfdr = min(npfdr, QMAN_PFDR_MAX); + bus_write_4(sc->sc_rres, QMAN_MCP0, 8); + bus_write_4(sc->sc_rres, QMAN_MCP1, npfdr - 9); + bus_write_4(sc->sc_rres, QMAN_MCR, MCR_INIT_PFDR); + + for (int timeout = 100000; timeout > 0; timeout--) { + DELAY(1); + res = bus_read_4(sc->sc_rres, QMAN_MCR); + if (res >= MCR_RSLT_OK) + break; + } - sc = app; + if (res < MCR_RSLT_OK) + return (EBUSY); + if (res == MCR_RSLT_OK) + return (0); - device_printf(sc->sc_dev, "dummy callback for rejected frame.\n"); - return (e_RX_STORE_RESPONSE_CONTINUE); + return (ENXIO); } int qman_attach(device_t dev) { struct qman_softc *sc; - t_QmParam qp; - t_Error error; - t_QmRevisionInfo rev; + int error; + vm_paddr_t fqd_pa, pfdr_pa; + vm_size_t fqd_sz, pfdr_sz; + int qman_channel_pool1 = QMAN_CHANNEL_POOL1_REV1; + uint32_t ver; + uint32_t nfqd; + bool qman3 = false; sc = device_get_softc(dev); sc->sc_dev = dev; qman_sc = sc; - if (XX_MallocSmartInit() != E_OK) { - device_printf(dev, "could not initialize smart allocator.\n"); - return (ENXIO); - } - - sched_pin(); - /* Allocate resources */ sc->sc_rrid = 0; - sc->sc_rres = bus_alloc_resource(dev, SYS_RES_MEMORY, - &sc->sc_rrid, 0, ~0, QMAN_CCSR_SIZE, RF_ACTIVE); + sc->sc_rres = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 0, RF_ACTIVE); if (sc->sc_rres == NULL) { device_printf(dev, "could not allocate memory.\n"); goto err; @@ -186,57 +329,79 @@ qman_attach(device_t dev) device_printf(dev, "could not allocate error interrupt.\n"); goto err; } + error = dpaa_map_private_memory(dev, 0, "fsl,qman-fqd", + &fqd_pa, &fqd_sz); + error = dpaa_map_private_memory(dev, 1, "fsl,qman-pfdr", + &pfdr_pa, &pfdr_sz); + + bzero((void *)PHYS_TO_DMAP(fqd_pa), fqd_sz); + cpu_flush_dcache((void *)PHYS_TO_DMAP(fqd_pa), fqd_sz); + /* + * FQDs are 64 bytes in size, with 24 bit pointers, so FQIDs are 24 + * bits, fits fine in a uint32_t. + */ + nfqd = fqd_sz / 64; + qman_total_fqids = nfqd; + qman_channel_base = qman_channel_pool1; + qman_fq_list = malloc(nfqd * sizeof(struct qman_fq *), M_QMAN, + M_WAITOK); - if (qp_sc == NULL) + error = qman_set_memory(sc, fqd_pa, fqd_sz, QMAN_FQD_BARE); + if (error != 0 && error != EEXIST) goto err; + error = qman_set_memory(sc, pfdr_pa, pfdr_sz, QMAN_PFDR_BARE); + if (error != 0 && error != EEXIST) + goto err; + if (error == 0) { + /* Initialize PFDRs if it hasn't been initialized before */ + error = qman_setup_pfdr(sc, pfdr_sz / 64); + if (error != 0) + goto err; + /* Magic constant from documentation */ + bus_write_4(sc->sc_rres, QMAN_PFDR_CFG, 64); + } - dpaa_portal_map_registers(qp_sc); + bus_write_4(sc->sc_rres, QMAN_ERR_ISR, 0xffffffff); + bus_write_4(sc->sc_rres, QMAN_ERR_IER, 0xffffffff); - /* Initialize QMan */ - qp.guestId = NCSW_MASTER_ID; - qp.baseAddress = rman_get_bushandle(sc->sc_rres); - qp.swPortalsBaseAddress = rman_get_bushandle(qp_sc->sc_rres[0]); - qp.liodn = 0; - qp.totalNumOfFqids = QMAN_MAX_FQIDS; - qp.fqdMemPartitionId = NCSW_MASTER_ID; - qp.pfdrMemPartitionId = NCSW_MASTER_ID; - qp.f_Exception = qman_exception; - qp.h_App = sc; - qp.errIrq = (uintptr_t)sc->sc_ires; - qp.partFqidBase = QMAN_FQID_BASE; - qp.partNumOfFqids = QMAN_MAX_FQIDS; - qp.partCgsBase = 0; - qp.partNumOfCgs = 0; + ver = bus_read_4(sc->sc_rres, QMAN_IP_REV_1); + sc->sc_qman_major = ((ver & IP_MJ_M) >> IP_MJ_S); + if (sc->sc_qman_major >= 3) + qman3 = true; - sc->sc_qh = QM_Config(&qp); - if (sc->sc_qh == NULL) { - device_printf(dev, "could not be configured\n"); - goto err; - } + if (qman3) + qman_channel_pool1 = QMAN_CHANNEL_POOL1_REV3; - error = QM_Init(sc->sc_qh); - if (error != E_OK) { - device_printf(dev, "could not be initialized\n"); + sc->sc_qman_base_channel = qman_channel_pool1; + + sc->sc_fqalloc = + vmem_create("qman-fqalloc", 1, nfqd - 1, 1, 0, M_WAITOK); + sc->sc_qpalloc = + vmem_create("qman-fqalloc", qman_channel_pool1, + QMAN_POOL_CHANNELS, 1, 0, M_WAITOK); + sc->sc_cgalloc = vmem_create("qman->cgalloc", 0, QMAN_CGRS, + 1, 0, M_WAITOK); + + if (bus_setup_intr(dev, sc->sc_ires, INTR_TYPE_NET, NULL, qman_isr, + sc, &sc->sc_intr_cookie) != 0) goto err; - } - error = QM_GetRevision(sc->sc_qh, &rev); - if (error != E_OK) { - device_printf(dev, "could not get QMan revision\n"); + if (error != 0) { + device_printf(dev, "could not be initialized\n"); goto err; } + bus_write_4(sc->sc_rres, QMAN_DCP_CFG(0), + qman3 ? DCP_CFG_ED_3 : DCP_CFG_ED); + bus_write_4(sc->sc_rres, QMAN_DCP_CFG(1), + qman3 ? DCP_CFG_ED_3 : DCP_CFG_ED); - device_printf(dev, "Hardware version: %d.%d.\n", - rev.majorRev, rev.minorRev); + bus_write_4(sc->sc_rres, 0xd00, 0x80000322); - sched_unpin(); - - qman_portal_setup(sc); + /* TODO: DO we need a taskqueue? Allocate here if so */ return (0); err: - sched_unpin(); qman_detach(dev); return (ENXIO); } @@ -248,11 +413,15 @@ qman_detach(device_t dev) sc = device_get_softc(dev); - if (sc->sc_qh) - QM_Free(sc->sc_qh); + if (sc->sc_fqalloc != NULL) + vmem_destroy(sc->sc_fqalloc); + if (sc->sc_qpalloc != NULL) + vmem_destroy(sc->sc_qpalloc); + if (sc->sc_cgalloc != NULL) + vmem_destroy(sc->sc_cgalloc); - if (sc->sc_ires != NULL) - XX_DeallocIntr((uintptr_t)sc->sc_ires); + if (sc->sc_intr_cookie != NULL) + bus_teardown_intr(dev, sc->sc_ires, sc->sc_intr_cookie); if (sc->sc_ires != NULL) bus_release_resource(dev, SYS_RES_IRQ, @@ -262,6 +431,9 @@ qman_detach(device_t dev) bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_rrid, sc->sc_rres); + free(qman_fq_list, M_QMAN); + qman_fq_list = NULL; + return (0); } @@ -286,261 +458,233 @@ qman_shutdown(device_t dev) return (0); } +int +qman_alloc_channel(void) +{ + struct qman_softc *sc = qman_sc; + vmem_addr_t channel; + + vmem_alloc(sc->sc_qpalloc, 1, M_BESTFIT | M_WAITOK, &channel); + + return (channel); +} + +void +qman_free_channel(int channel) +{ + struct qman_softc *sc = qman_sc; + + vmem_free(sc->sc_qpalloc, channel, 1); +} /** * @group QMan API functions implementation. * @{ */ -t_Handle -qman_fqr_create(uint32_t fqids_num, e_QmFQChannel channel, uint8_t wq, +struct qman_fq * +qman_fq_from_index(uint32_t fqid) +{ + if (fqid > qman_total_fqids) + return (NULL); + return (qman_fq_list[fqid]); +} + +/* Allocate and initialize an FQ Range */ +struct qman_fq * +qman_fq_create(uint32_t fqids_num, int channel, uint8_t wq, bool force_fqid, uint32_t fqid_or_align, bool init_parked, bool hold_active, bool prefer_in_cache, bool congst_avoid_ena, - t_Handle congst_group, int8_t overhead_accounting_len, + void *congst_group, int8_t overhead_accounting_len, uint32_t tail_drop_threshold) { + union qman_mc_command cmd; struct qman_softc *sc; - t_QmFqrParams fqr; - t_Handle fqrh, portal; + union qman_mc_result *res; + struct qman_fq *fqh; + device_t portal; + vmem_addr_t fqid_base; + uint8_t rslt; sc = qman_sc; - sched_pin(); - - /* Ensure we have got QMan port initialized */ - portal = qman_portal_setup(sc); - if (portal == NULL) { - device_printf(sc->sc_dev, "could not setup QMan portal\n"); - goto err; + if (fqids_num != 1) { + device_printf(sc->sc_dev, + "Only one fq allocation allowed currently\n"); + return (NULL); } - fqr.h_Qm = sc->sc_qh; - fqr.h_QmPortal = portal; - fqr.initParked = init_parked; - fqr.holdActive = hold_active; - fqr.preferInCache = prefer_in_cache; + bzero(&cmd, sizeof(cmd)); + vmem_alloc(sc->sc_fqalloc, fqids_num, M_BESTFIT | M_WAITOK, &fqid_base); + cmd.init_fq.fqid = fqid_base; + cmd.init_fq.count = fqids_num - 1; + cmd.init_fq.dest_chan = channel; + cmd.init_fq.dest_wq = wq; + cmd.init_fq.we_mask = QCSP_INIT_FQ_WE_DEST_WQ | QCSP_INIT_FQ_WE_FQ_CTRL; + if (init_parked) + cmd.init_fq.verb = QCSP_VERB_INIT_FQ_PARK; + else + cmd.init_fq.verb = QCSP_VERB_INIT_FQ_SCHED; + cmd.init_fq.fq_ctrl = (prefer_in_cache ? QM_FQCTRL_LIC : 0) | + (hold_active ? QM_FQCTRL_HOLDACTIVE : 0) | + (congst_avoid_ena ? QM_FQCTRL_AVOIDBLOCK : 0); - /* We do not support stashing */ - fqr.useContextAForStash = FALSE; - fqr.p_ContextA = 0; - fqr.p_ContextB = 0; + critical_enter(); - fqr.channel = channel; - fqr.wq = wq; - fqr.shadowMode = FALSE; - fqr.numOfFqids = fqids_num; + /* Ensure we have got QMan port initialized */ + portal = DPCPU_GET(qman_affine_portal); + res = QMAN_PORTAL_MC_SEND_RAW(portal, &cmd); - /* FQID */ - fqr.useForce = force_fqid; - if (force_fqid) { - fqr.qs.frcQ.fqid = fqid_or_align; - } else { - fqr.qs.nonFrcQs.align = fqid_or_align; - } + rslt = 0; + if (res != NULL) + rslt = res->init_fq.rslt; - /* Congestion Avoidance */ - fqr.congestionAvoidanceEnable = congst_avoid_ena; - if (congst_avoid_ena) { - fqr.congestionAvoidanceParams.h_QmCg = congst_group; - fqr.congestionAvoidanceParams.overheadAccountingLength = - overhead_accounting_len; - fqr.congestionAvoidanceParams.fqTailDropThreshold = - tail_drop_threshold; - } else { - fqr.congestionAvoidanceParams.h_QmCg = 0; - fqr.congestionAvoidanceParams.overheadAccountingLength = 0; - fqr.congestionAvoidanceParams.fqTailDropThreshold = 0; - } - - fqrh = QM_FQR_Create(&fqr); - if (fqrh == NULL) { - device_printf(sc->sc_dev, "could not create Frame Queue Range" - "\n"); + critical_exit(); + if (res == NULL || rslt != QMAN_MC_RES_OK) { + vmem_free(sc->sc_fqalloc, fqid_base, fqids_num); goto err; } - sc->sc_fqr_cpu[QM_FQR_GetFqid(fqrh)] = PCPU_GET(cpuid); + fqh = malloc(sizeof(*fqh), M_QMAN, M_WAITOK | M_ZERO); + fqh->fqid = fqid_base; - sched_unpin(); + qman_fq_list[fqid_base] = fqh; - return (fqrh); + return (fqh); err: - sched_unpin(); return (NULL); } -t_Error -qman_fqr_free(t_Handle fqr) +static int +qman_fq_retire(device_t portal, struct qman_fq *fq) { - struct qman_softc *sc; - t_Error error; - - sc = qman_sc; - thread_lock(curthread); - sched_bind(curthread, sc->sc_fqr_cpu[QM_FQR_GetFqid(fqr)]); - thread_unlock(curthread); + union qman_mc_command cmd; + union qman_mc_result *rr; - error = QM_FQR_Free(fqr); + bzero(&cmd, sizeof(cmd)); - thread_lock(curthread); - sched_unbind(curthread); - thread_unlock(curthread); + cmd.alter_fqs.verb = QCSP_VERB_ALTER_FQ_RETIRE; + cmd.alter_fqs.fqid = fq->fqid; + rr = QMAN_PORTAL_MC_SEND_RAW(portal, &cmd); + if (rr == NULL) + return (ETIMEDOUT); - return (error); -} - -t_Error -qman_fqr_register_cb(t_Handle fqr, t_QmReceivedFrameCallback *callback, - t_Handle app) -{ - struct qman_softc *sc; - t_Error error; - t_Handle portal; - - sc = qman_sc; - sched_pin(); - - /* Ensure we have got QMan port initialized */ - portal = qman_portal_setup(sc); - if (portal == NULL) { - device_printf(sc->sc_dev, "could not setup QMan portal\n"); - sched_unpin(); - return (E_NOT_SUPPORTED); + if (rr->alter_fqs.rslt == QMAN_MC_RES_OK) { + if (rr->alter_fqs.fqs & QMAN_MC_AFQS_NE) { + /* TODO: Drain.... */ + } + return (0); } - error = QM_FQR_RegisterCB(fqr, callback, app); - - sched_unpin(); - - return (error); + return (0); } -t_Error -qman_fqr_enqueue(t_Handle fqr, uint32_t fqid_off, t_DpaaFD *frame) +int +qman_fq_free(struct qman_fq *fq) { struct qman_softc *sc; - t_Error error; - t_Handle portal; + int error; sc = qman_sc; - sched_pin(); - - /* Ensure we have got QMan port initialized */ - portal = qman_portal_setup(sc); - if (portal == NULL) { - device_printf(sc->sc_dev, "could not setup QMan portal\n"); - sched_unpin(); - return (E_NOT_SUPPORTED); - } - - error = QM_FQR_Enqueue(fqr, portal, fqid_off, frame); - sched_unpin(); + critical_enter(); + error = qman_fq_retire(DPCPU_GET(qman_affine_portal), fq); + /* TODO: Take FQ out of service. */ + critical_exit(); + if (error != 0) + return (error); + vmem_free(sc->sc_fqalloc, fq->fqid, 1); + qman_fq_list[fq->fqid] = NULL; + free(fq, M_QMAN); - return (error); + return (0); } -uint32_t -qman_fqr_get_counter(t_Handle fqr, uint32_t fqid_off, - e_QmFqrCounters counter) +int +qman_fq_register_cb(struct qman_fq *fq, qman_cb_dqrr callback, + void *ctx) { - struct qman_softc *sc; - uint32_t val; - t_Handle portal; - - sc = qman_sc; - sched_pin(); - - /* Ensure we have got QMan port initialized */ - portal = qman_portal_setup(sc); - if (portal == NULL) { - device_printf(sc->sc_dev, "could not setup QMan portal\n"); - sched_unpin(); - return (0); - } + fq->cb.dqrr = callback; + fq->cb.ctx = ctx; - val = QM_FQR_GetCounter(fqr, portal, fqid_off, counter); - - sched_unpin(); - - return (val); + return (0); } -t_Error -qman_fqr_pull_frame(t_Handle fqr, uint32_t fqid_off, t_DpaaFD *frame) +int +qman_fq_enqueue(struct qman_fq *fq, struct dpaa_fd *frame) { struct qman_softc *sc; - t_Error error; - t_Handle portal; + int error; + void *portal; sc = qman_sc; - sched_pin(); + critical_enter(); /* Ensure we have got QMan port initialized */ - portal = qman_portal_setup(sc); + portal = DPCPU_GET(qman_affine_portal); if (portal == NULL) { device_printf(sc->sc_dev, "could not setup QMan portal\n"); - sched_unpin(); - return (E_NOT_SUPPORTED); + critical_exit(); + return (ENXIO); } - error = QM_FQR_PullFrame(fqr, portal, fqid_off, frame); + error = QMAN_PORTAL_ENQUEUE(portal, fq, frame); - sched_unpin(); + critical_exit(); return (error); } uint32_t -qman_fqr_get_base_fqid(t_Handle fqr) +qman_fq_get_fqid(struct qman_fq *fq) { - struct qman_softc *sc; - uint32_t val; - t_Handle portal; + return (fq->fqid); +} - sc = qman_sc; - sched_pin(); - /* Ensure we have got QMan port initialized */ - portal = qman_portal_setup(sc); - if (portal == NULL) { - device_printf(sc->sc_dev, "could not setup QMan portal\n"); - sched_unpin(); - return (0); - } +uint32_t +qman_fq_get_counter(struct qman_fq *fq, int counter) +{ + union qman_mc_result *cmd_res; + union qman_mc_command command; + device_t portal; + u_int ret = 0; - val = QM_FQR_GetFqid(fqr); + bzero(&command, sizeof(command)); + command.query_fq_np.verb = QCSP_VERB_QUERY_FQ_NP; + command.query_fq_np.fqid = fq->fqid; + critical_enter(); + portal = DPCPU_GET(qman_affine_portal); + cmd_res = QMAN_PORTAL_MC_SEND_RAW(portal, &command); + if (counter == QMAN_COUNTER_FRAME) + ret = cmd_res->query_fq_np.frm_cnt; + else if (counter == QMAN_COUNTER_BYTES) + ret = cmd_res->query_fq_np.byte_cnt; - sched_unpin(); + critical_exit(); - return (val); + return (ret); } -t_Error -qman_poll(e_QmPortalPollSource source) +void +qman_set_sdest(uint16_t channel, int cpu) { - struct qman_softc *sc; - t_Error error; - t_Handle portal; - - sc = qman_sc; - sched_pin(); + struct qman_softc *sc = qman_sc; + uint32_t reg; - /* Ensure we have got QMan port initialized */ - portal = qman_portal_setup(sc); - if (portal == NULL) { - device_printf(sc->sc_dev, "could not setup QMan portal\n"); - sched_unpin(); - return (E_NOT_SUPPORTED); + if (sc->sc_qman_major >= 3) { + reg = bus_read_4(sc->sc_rres, QCSP_IO_CFG_3(channel)); + reg &= IO_CFG_SDEST_M; + reg |= (cpu << IO_CFG_SDEST_S); + bus_write_4(sc->sc_rres, QCSP_IO_CFG_3(channel), reg); + } else { + reg = bus_read_4(sc->sc_rres, QCSP_IO_CFG(channel)); + reg &= IO_CFG_SDEST_M; + reg |= (cpu << IO_CFG_SDEST_S); + bus_write_4(sc->sc_rres, QCSP_IO_CFG(channel), reg); } - - error = QM_Poll(sc->sc_qh, source); - - sched_unpin(); - - return (error); } /* diff --git a/sys/dev/dpaa/qman.h b/sys/dev/dpaa/qman.h index 815ef1f6d33a..0e841dbc6ae6 100644 --- a/sys/dev/dpaa/qman.h +++ b/sys/dev/dpaa/qman.h @@ -27,10 +27,13 @@ #ifndef _QMAN_H #define _QMAN_H +#include <sys/vmem.h> #include <machine/vmparam.h> -#include <contrib/ncsw/inc/Peripherals/qm_ext.h> - +struct qman_fq; +struct qman_fq; +struct dpaa_fd; +struct qman_portal; /** * @group QMan private defines/declarations @@ -44,13 +47,15 @@ /** * Pool channel common to all software portals. * @note Value of 0 reflects the e_QM_FQ_CHANNEL_POOL1 from e_QmFQChannel - * type used in qman_fqr_create(). + * type used in qman_fq_create(). */ #define QMAN_COMMON_POOL_CHANNEL 0 #define QMAN_FQID_BASE 1 -#define QMAN_CCSR_SIZE 0x1000 +/* Counters */ +#define QMAN_COUNTER_FRAME 0 +#define QMAN_COUNTER_BYTES 1 /* * Portal defines @@ -69,18 +74,103 @@ struct qman_softc { struct resource *sc_rres; /* register resource */ int sc_irid; /* interrupt rid */ struct resource *sc_ires; /* interrupt resource */ + vmem_t *sc_fqalloc; + vmem_t *sc_qpalloc; + vmem_t *sc_cgalloc; + void *sc_intr_cookie; + int sc_qman_base_channel; + int sc_qman_major; - bool sc_regs_mapped[MAXCPU]; - - t_Handle sc_qh; /* QMAN handle */ - t_Handle sc_qph[MAXCPU]; /* QMAN portal handles */ vm_paddr_t sc_qp_pa; /* QMAN portal PA */ - int sc_fqr_cpu[QMAN_MAX_FQIDS]; + int sc_fq_cpu[QMAN_MAX_FQIDS]; +}; + +struct qman_fd { + uint64_t dd:2; + uint64_t liodn_off:6; + uint64_t bpid:8; + uint64_t eliodn_off:4; + uint64_t _rsvd0:4; + uint64_t addr:40; + union { + struct { + uint32_t format:3; + uint32_t offset:9; + uint32_t length:20; + }; + struct { + uint32_t format2:3; + uint32_t wlength:29; + }; + }; + uint32_t cmd_stat; +}; + +_Static_assert(sizeof(struct qman_fd) == 16, "qman_fd size mismatch"); + +struct qman_dqrr_entry { + uint8_t verb; + uint8_t stat; + uint16_t seqnum; + uint8_t tok; + uint8_t _rsvd0[3]; + uint32_t fqid; + uint32_t ctxb; + struct qman_fd fd; + uint8_t _rsvd1[32]; +}; + +/* Bits for qman_dqrr_entry fields */ +#define QMAN_DQRR_STAT_FQ_EMPTY 0x80 +#define QMAN_DQRR_STAT_FQ_HELD_ACTIVE 0x40 +#define QMAN_DQRR_STAT_FQ_FORCED 0x20 +#define QMAN_DQRR_STAT_HAS_FRAME 0x10 +#define QMAN_DQRR_STAT_VDQCR 0x02 +#define QMAN_DQRR_STAT_EXPIRED 0x01 + +struct qman_mr_entry { + union { + struct { + uint8_t verb; + uint8_t data[63]; + }; + struct { + uint8_t verb; + uint8_t dca; + uint16_t seqnum; + uint32_t rc:8; + uint32_t orp:24; + uint32_t fqid; + uint32_t tag; + struct qman_fd fd; + uint8_t _rsvd[32]; + } ern; + struct { + uint8_t verb; + uint8_t fqs; + uint8_t _rsvd0[6]; + uint32_t fqid; + uint32_t ctxb; + uint8_t _rsvd1[48]; + } fqscn; + }; }; + +_Static_assert(sizeof(struct qman_mr_entry) == 64, "bad sizeof qman_mr"); /** @> */ +typedef int (*qman_cb_dqrr)(device_t, struct qman_fq *, + struct qman_fd *, void *); +typedef void (*qman_cb_mr)(device_t, struct qman_fq *, + struct qman_mr_entry *); +struct qman_cb { + qman_cb_dqrr dqrr; + qman_cb_mr ern; + qman_cb_mr fqscn; + void *ctx; +}; /** * @group QMan bus interface * @{ @@ -91,6 +181,8 @@ int qman_suspend(device_t dev); int qman_resume(device_t dev); int qman_shutdown(device_t dev); /** @> */ +int qman_create_affine_portal(device_t, vm_offset_t, vm_offset_t, int); +void qman_set_sdest(uint16_t, int); /** @@ -149,69 +241,77 @@ int qman_shutdown(device_t dev); * * @return A handle to newly created FQR object. */ -t_Handle qman_fqr_create(uint32_t fqids_num, e_QmFQChannel channel, uint8_t wq, - bool force_fqid, uint32_t fqid_or_align, bool init_parked, +struct qman_fq *qman_fq_create(uint32_t fqids_num, int channel, + uint8_t wq, bool force_fqid, uint32_t fqid_or_align, bool init_parked, bool hold_active, bool prefer_in_cache, bool congst_avoid_ena, - t_Handle congst_group, int8_t overhead_accounting_len, + void *congst_group, int8_t overhead_accounting_len, uint32_t tail_drop_threshold); /** * Free Frame Queue Range. * - * @param fqr A handle to FQR to be freed. + * @param fq A handle to FQR to be freed. * @return E_OK on success; error code otherwise. */ -t_Error qman_fqr_free(t_Handle fqr); +int qman_fq_free(struct qman_fq *fq); /** * Register the callback function. * The callback function will be called when a frame comes from this FQR. * - * @param fqr A handle to FQR. + * @param fq A handle to FQR. * @param callback A pointer to the callback function. * @param app A pointer to the user's data. * @return E_OK on success; error code otherwise. */ -t_Error qman_fqr_register_cb(t_Handle fqr, t_QmReceivedFrameCallback *callback, - t_Handle app); +int qman_fq_register_cb(struct qman_fq *fq, qman_cb_dqrr callback, + void *ctx); /** - * Enqueue a frame on a given FQR. + * Enqueue a frame on a given FQ. * - * @param fqr A handle to FQR. - * @param fqid_off FQID offset wihin the FQR. + * @param fq A handle to FQ. * @param frame A frame to be enqueued to the transmission. * @return E_OK on success; error code otherwise. */ -t_Error qman_fqr_enqueue(t_Handle fqr, uint32_t fqid_off, t_DpaaFD *frame); +int qman_fq_enqueue(struct qman_fq *fq, struct dpaa_fd *frame); /** - * Get one of the FQR counter's value. + * Get one of the FQ counter's value. * - * @param fqr A handle to FQR. - * @param fqid_off FQID offset within the FQR. + * @param fq A handle to FQ. * @param counter The requested counter. * @return Counter's current value. */ -uint32_t qman_fqr_get_counter(t_Handle fqr, uint32_t fqid_off, - e_QmFqrCounters counter); +uint32_t qman_fq_get_counter(struct qman_fq *fq, int counter); /** - * Pull frame from FQR. + * Pull frame from FQ. * - * @param fqr A handle to FQR. - * @param fqid_off FQID offset within the FQR. + * @param fq A handle to FQ. * @param frame The received frame. * @return E_OK on success; error code otherwise. */ -t_Error qman_fqr_pull_frame(t_Handle fqr, uint32_t fqid_off, t_DpaaFD *frame); +int qman_fq_pull_frame(struct qman_fq *fq, struct dpaa_fd *frame); /** - * Get base FQID of the FQR. - * @param fqr A handle to FQR. - * @return Base FQID of the FQR. + * Get FQID of the FQ. + * @param fq A handle to FQ. + * @return FQID of the FQ. + */ +uint32_t qman_fq_get_fqid(struct qman_fq *fq); + +/* + * Allocate a QMan channel to be used with an FQ. + * @return Channel ID + */ +int qman_alloc_channel(void); + +/* + * Free a channel + * @param chan Channel ID returned from qman_alloc_channel(). */ -uint32_t qman_fqr_get_base_fqid(t_Handle fqr); +void qman_free_channel(int); /** * Poll frames from QMan. @@ -220,24 +320,24 @@ uint32_t qman_fqr_get_base_fqid(t_Handle fqr); * @param source Type of frames to be polled. * @return E_OK on success; error otherwise. */ -t_Error qman_poll(e_QmPortalPollSource source); +int qman_poll(int source); /** * General received frame callback. * This is called, when user did not register his own callback for a given - * frame queue range (fqr). + * frame queue range (fq). */ -e_RxStoreResponse qman_received_frame_callback(t_Handle app, t_Handle qm_fqr, - t_Handle qm_portal, uint32_t fqid_offset, t_DpaaFD *frame); +int qman_received_frame_callback(void *ctx, struct qman_fq *fq, + void *qm_portal, uint32_t fqid_offset, struct dpaa_fd *frame); /** * General rejected frame callback. * This is called, when user did not register his own callback for a given - * frame queue range (fqr). + * frame queue range (fq). */ -e_RxStoreResponse qman_rejected_frame_callback(t_Handle app, t_Handle qm_fqr, - t_Handle qm_portal, uint32_t fqid_offset, t_DpaaFD *frame, - t_QmRejectedFrameInfo *qm_rejected_frame_info); +int qman_rejected_frame_callback(void *ctx, struct qman_fq *fq, + void *qm_portal, uint32_t fqid_offset, struct dpaa_fd *frame, + void *qm_rejected_frame_info); /** @} */ diff --git a/sys/dev/dpaa/qman_fdt.c b/sys/dev/dpaa/qman_fdt.c index 89bf802e0067..3536042abf9c 100644 --- a/sys/dev/dpaa/qman_fdt.c +++ b/sys/dev/dpaa/qman_fdt.c @@ -41,6 +41,8 @@ #include "qman.h" #include "portals.h" +#include "qman_var.h" +#include "qman_portal_if.h" #define FQMAN_DEVSTR "Freescale Queue Manager" @@ -59,12 +61,7 @@ static device_method_t qman_methods[] = { DEVMETHOD_END }; -static driver_t qman_driver = { - "qman", - qman_methods, - sizeof(struct qman_softc), -}; - +DEFINE_CLASS_0(qman, qman_driver, qman_methods, sizeof(struct qman_softc)); EARLY_DRIVER_MODULE(qman, simplebus, qman_driver, 0, 0, BUS_PASS_SUPPORTDEV); static int @@ -82,53 +79,38 @@ qman_fdt_probe(device_t dev) /* * QMAN Portals */ -#define QMAN_PORT_DEVSTR "Freescale Queue Manager - Portals" +#define QMAN_PORT_DEVSTR "Freescale Queue Manager - Portal" -static device_probe_t qman_portals_fdt_probe; -static device_attach_t qman_portals_fdt_attach; +static int portal_ncpus; +static device_probe_t qman_portal_fdt_probe; +static device_attach_t qman_portal_fdt_attach; -static device_method_t qm_portals_methods[] = { +static device_method_t qman_portal_methods[] = { /* Device interface */ - DEVMETHOD(device_probe, qman_portals_fdt_probe), - DEVMETHOD(device_attach, qman_portals_fdt_attach), - DEVMETHOD(device_detach, qman_portals_detach), + DEVMETHOD(device_probe, qman_portal_fdt_probe), + DEVMETHOD(device_attach, qman_portal_fdt_attach), + DEVMETHOD(device_detach, qman_portal_detach), - DEVMETHOD_END -}; + DEVMETHOD(qman_portal_enqueue, qman_portal_fq_enqueue), + DEVMETHOD(qman_portal_mc_send_raw, qman_portal_mc_send_raw), + DEVMETHOD(qman_portal_static_dequeue_channel, + qman_portal_static_dequeue_channel), + DEVMETHOD(qman_portal_static_dequeue_rm_channel, + qman_portal_static_dequeue_rm_channel), -static driver_t qm_portals_driver = { - "qman-portals", - qm_portals_methods, - sizeof(struct dpaa_portals_softc), + DEVMETHOD_END }; -EARLY_DRIVER_MODULE(qman_portals, ofwbus, qm_portals_driver, 0, 0, - BUS_PASS_BUS); - -static void -get_addr_props(phandle_t node, uint32_t *addrp, uint32_t *sizep) -{ - - *addrp = 2; - *sizep = 1; - OF_getencprop(node, "#address-cells", addrp, sizeof(*addrp)); - OF_getencprop(node, "#size-cells", sizep, sizeof(*sizep)); -} +DEFINE_CLASS_0(qman_portal, qman_portal_driver, qman_portal_methods, + sizeof(struct qman_softc)); +EARLY_DRIVER_MODULE(qman_portal, simplebus, qman_portal_driver, 0, 0, + BUS_PASS_SUPPORTDEV + BUS_PASS_ORDER_MIDDLE); static int -qman_portals_fdt_probe(device_t dev) +qman_portal_fdt_probe(device_t dev) { - phandle_t node; - if (ofw_bus_is_compatible(dev, "simple-bus")) { - node = ofw_bus_get_node(dev); - for (node = OF_child(node); node > 0; node = OF_peer(node)) { - if (ofw_bus_node_is_compatible(node, "fsl,qman-portal")) - break; - } - if (node <= 0) - return (ENXIO); - } else if (!ofw_bus_is_compatible(dev, "fsl,qman-portals")) + if (!ofw_bus_is_compatible(dev, "fsl,qman-portal")) return (ENXIO); device_set_desc(dev, QMAN_PORT_DEVSTR); @@ -137,105 +119,15 @@ qman_portals_fdt_probe(device_t dev) } static int -qman_portals_fdt_attach(device_t dev) +qman_portal_fdt_attach(device_t dev) { - struct dpaa_portals_softc *sc; - phandle_t node, child, cpu_node; - vm_paddr_t portal_pa, portal_par_pa; - vm_size_t portal_size; - uint32_t addr, paddr, size; - ihandle_t cpu; - int cpu_num, cpus, intr_rid; - struct dpaa_portals_devinfo di; - struct ofw_bus_devinfo ofw_di = {}; - cell_t *range; - int nrange; - int i; - - cpus = 0; - sc = device_get_softc(dev); - sc->sc_dev = dev; - - node = ofw_bus_get_node(dev); - - /* Get this node's range */ - get_addr_props(ofw_bus_get_node(device_get_parent(dev)), &paddr, &size); - get_addr_props(node, &addr, &size); + int portal_cpu = portal_ncpus; - nrange = OF_getencprop_alloc_multi(node, "ranges", - sizeof(*range), (void **)&range); - if (nrange < addr + paddr + size) + /* Don't attach to more portals than we have CPUs */ + if (mp_ncpus == portal_ncpus) return (ENXIO); - portal_pa = portal_par_pa = 0; - portal_size = 0; - for (i = 0; i < addr; i++) { - portal_pa <<= 32; - portal_pa |= range[i]; - } - for (; i < paddr + addr; i++) { - portal_par_pa <<= 32; - portal_par_pa |= range[i]; - } - portal_pa += portal_par_pa; - for (; i < size + paddr + addr; i++) { - portal_size = (uintmax_t)portal_size << 32; - portal_size |= range[i]; - } - OF_prop_free(range); - sc->sc_dp_size = portal_size; - sc->sc_dp_pa = portal_pa; - - /* Find portals tied to CPUs */ - for (child = OF_child(node); child != 0; child = OF_peer(child)) { - if (cpus >= mp_ncpus) - break; - if (!ofw_bus_node_is_compatible(child, "fsl,qman-portal")) { - continue; - } - /* Checkout related cpu */ - if (OF_getprop(child, "cpu-handle", (void *)&cpu, - sizeof(cpu)) > 0) { - cpu_node = OF_instance_to_package(cpu); - /* Acquire cpu number */ - if (OF_getencprop(cpu_node, "reg", &cpu_num, sizeof(cpu_num)) <= 0) { - device_printf(dev, "Could not retrieve CPU number.\n"); - return (ENXIO); - } - } else - cpu_num = cpus; - cpus++; - - if (ofw_bus_gen_setup_devinfo(&ofw_di, child) != 0) { - device_printf(dev, "could not set up devinfo\n"); - continue; - } - - resource_list_init(&di.di_res); - if (ofw_bus_reg_to_rl(dev, child, addr, size, &di.di_res)) { - device_printf(dev, "%s: could not process 'reg' " - "property\n", ofw_di.obd_name); - ofw_bus_gen_destroy_devinfo(&ofw_di); - continue; - } - if (ofw_bus_intr_to_rl(dev, child, &di.di_res, &intr_rid)) { - device_printf(dev, "%s: could not process " - "'interrupts' property\n", ofw_di.obd_name); - resource_list_free(&di.di_res); - ofw_bus_gen_destroy_devinfo(&ofw_di); - continue; - } - di.di_intr_rid = intr_rid; - - if (dpaa_portal_alloc_res(dev, &di, cpu_num)) - goto err; - } - ofw_bus_gen_destroy_devinfo(&ofw_di); + portal_ncpus++; - return (qman_portals_attach(dev)); -err: - resource_list_free(&di.di_res); - ofw_bus_gen_destroy_devinfo(&ofw_di); - qman_portals_detach(dev); - return (ENXIO); + return (qman_portal_attach(dev, portal_cpu)); } diff --git a/sys/dev/dpaa/qman_portal_if.m b/sys/dev/dpaa/qman_portal_if.m new file mode 100644 index 000000000000..2efe31dd6980 --- /dev/null +++ b/sys/dev/dpaa/qman_portal_if.m @@ -0,0 +1,37 @@ +# +# Copyright (c) 2026 Justin Hibbits +# +# SPDX-License-Identifier: BSD-2-Clause + +#include <sys/pcpu.h> +#include <machine/bus.h> +#include <dev/dpaa/portals.h> +#include <dev/dpaa/qman.h> +#include <dev/dpaa/qman_var.h> + +/** + * @brief DPAA QMan portal interface + * + */ +INTERFACE qman_portal; + +METHOD int enqueue { + device_t dev; + struct qman_fq *fq; + struct dpaa_fd *fd; +}; + +METHOD union qman_mc_result * mc_send_raw { + device_t dev; + union qman_mc_command *cmd; +}; + +METHOD void static_dequeue_channel { + device_t dev; + int channel; +} + +METHOD void static_dequeue_rm_channel { + device_t dev; + int channel; +} diff --git a/sys/dev/dpaa/qman_portals.c b/sys/dev/dpaa/qman_portals.c index 0f00a9f1a173..3b64aca71cb7 100644 --- a/sys/dev/dpaa/qman_portals.c +++ b/sys/dev/dpaa/qman_portals.c @@ -1,27 +1,7 @@ -/*- - * Copyright (c) 2012 Semihalf. - * All rights reserved. +/* + * Copyright (c) 2026 Justin Hibbits * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. + * SPDX-License-Identifier: BSD-2-Clause */ #include "opt_platform.h" @@ -36,6 +16,7 @@ #include <sys/proc.h> #include <sys/pcpu.h> #include <sys/sched.h> +#include <ddb/ddb.h> #include <machine/bus.h> #include <machine/tlb.h> @@ -47,143 +28,412 @@ #include "qman.h" #include "portals.h" +#include "qman_var.h" + + +/* Cache-enabled registers */ +#define QCSP_EQCR_N(n) (0x0000 + (n * 64)) +#define QMAN_EQCR_COUNT 8 +#define QCSP_DQRR_N(n) (0x1000 + (n * 64)) +#define QMAN_DQRR_COUNT 16 +#define QCSP_MR_N(n) (0x2000 + (n * 64)) +#define QMAN_MR_COUNT 8 +#define QCSP_CR 0x3800 +#define QCSP_RR(n) (0x3900 + 0x40 * (n)) + +#define QCSP_EQCR_PI_CENA 0x0000 +#define EQCR_PI_VP 0x00000008 +#define EQCR_PI_PI_M 0x00000007 +#define QCSP_EQCR_CI_CENA 0x0004 +#define EQCR_CI_C 0x00000008 +#define EQCR_CI_CI_M 0x00000007 +#define QCSP_DQRR_PI_CENA 0x0000 +#define DQRR_PI_VP 0x00000010 +#define DQRR_PI_PI_M 0x0000000f +#define QCSP_DQRR_CI_CENA 0x0004 +#define DQRR_CI_C 0x00000010 +#define DQRR_CI_CI_M 0x0000000f + +#define QMAN_MC_VERB_VBIT 0x80 + + +/* Cache-inhibited registers */ +#define QCSP_EQCR_PI_CINH 0x0000 +#define QCSP_EQCR_CI_CINH 0x0004 +#define QCSP_DQRR_PI_CINH 0x0040 +#define QCSP_DQRR_CI_CINH 0x0044 +#define QCSP_EQCR_ITR 0x0008 +#define QCSP_DQRR_ITR 0x0048 +#define QCSP_DQRR_SDQCR 0x0054 +#define SDQCR_SS 0x40000000 +#define SDQCR_FC 0x20000000 +#define SDQCR_DP 0x10000000 +#define SDQCR_DCT_NUL 0x00000000 +#define SDQCR_DCT_PRI_PREC 0x01000000 +#define SDQCR_DCT_ACTIVE_WQ 0x02000000 +#define SDQCR_DCT_ACTIVE_FQ_O 0x03000000 +#define SDQCR_DCT_M 0x03000000 +#define SDQCR_TOKEN_M 0x00ff0000 +#define SDQCR_TOKEN_S 16 +#define DQRR_DQ_SRC_M 0x0000ffff +#define DQRR_DQ_SRC_DCP 0x00008000 +#define SDQCR_DQ_SRC_CHAN(n) (0x8000 >> (n + 1)) +#define QCSP_DQRR_VDQCR 0x0058 +#define QCSP_DQRR_PDQCR 0x005c +#define QCSP_MR_ITR 0x0088 +#define QCSP_CFG 0x0100 +#define CFG_EST_M 0x70000000 +#define CFG_EST_S 28 +#define CFG_EP 0x04000000 +#define CFG_EPM_M 0x03000000 +#define CFG_EPM_PI_CI 0x00000000 +#define CFG_EPM_PI_CE 0x01000000 +#define CFG_EPM_VB1 0x02000000 +#define CFG_EPM_VB2 0x03000000 +#define CFG_DQRR_MF_M 0x00f00000 +#define CFG_DQRR_MF_S 20 +#define CFG_DP 0x00040000 +#define CFG_DCM_C_M 0x00030000 +#define CFG_DCM_CI_CI 0x00000000 +#define CFG_DCM_CI_CE 0x00010000 +#define CFG_DCM_DCA1 0x00020000 +#define CFG_DCM_DCA2 0x00030000 +#define CFG_SD 0x00000200 +#define CFG_MM 0x00000100 +#define CFG_RE 0x00000080 +#define CFG_RP 0x00000040 +#define CFG_SE 0x00000020 +#define CFG_SP 0x00000010 +#define CFG_SDEST_M 0x00000007 +#define QCSP_ISR 0x0e00 +#define QM_PIRQ_CSCI 0x00100000 +#define QM_PIRQ_EQCI 0x00080000 +#define QM_PIRQ_EQRI 0x00040000 +#define QM_PIRQ_DQRI 0x00020000 +#define QM_PIRQ_MRI 0x00010000 +#define QM_PIRQ_DQ_AVAIL_M 0x0000ffff +#define QCSP_IER 0x0e04 +#define QCSP_ISDR 0x0e08 +#define QCSP_IIR 0xe0c + +#define QM_EQCR_VERB_CMD_ENQUEUE 0x01 +#define QM_EQCR_VERB_BIT_INT 0x04 + +#define DEF_SDQCR_TOKEN 0xab -extern e_RxStoreResponse qman_received_frame_callback(t_Handle, t_Handle, - t_Handle, uint32_t, t_DpaaFD *); -extern e_RxStoreResponse qman_rejected_frame_callback(t_Handle, t_Handle, - t_Handle, uint32_t, t_DpaaFD *, t_QmRejectedFrameInfo *); +static void qman_portal_loop_rings(struct qman_portal_softc *sc); +static void qman_portal_isr(void *); -t_Handle qman_portal_setup(struct qman_softc *); +DPCPU_DEFINE(device_t, qman_affine_portal); +DPAA_RING(qman_eqcr, QMAN_EQCR_COUNT, QCSP_EQCR_PI_CENA, QCSP_EQCR_CI_CENA, + QCSP_EQCR_PI_CINH, QCSP_EQCR_CI_CINH); +DPAA_RING(qman_dqrr, QMAN_DQRR_COUNT, QCSP_DQRR_PI_CENA, QCSP_DQRR_CI_CENA, + QCSP_DQRR_PI_CINH, QCSP_DQRR_CI_CINH); -struct dpaa_portals_softc *qp_sc; +/* + * pmode: one of the CFG_EPM constants. + * stash_prio: 0 or CFG_EP + * stash_thresh: 0-7 + */ +static int +qman_eqcr_init(struct qman_portal_softc *sc, int pmode, u_int stash_thresh, + u_int stash_prio) +{ + struct resource *regs = sc->sc_base.sc_mres[1]; + uint32_t reg; + + sc->sc_eqcr.ring = + (struct qman_eqcr_entry *)(sc->sc_base.sc_ce_va + QCSP_EQCR_N(0)); + qman_eqcr_ring_init(&sc->sc_eqcr, &sc->sc_base); + reg = bus_read_4(regs, QCSP_CFG); + reg &= 0x00ffffff; + reg |= pmode; + reg |= ((stash_thresh << CFG_EST_S) & CFG_EST_M); + reg |= stash_prio; + + bus_write_4(regs, QCSP_CFG, reg); + return (0); +} + +static int +qman_dqrr_init(struct qman_portal_softc *sc) +{ + struct resource *regs = sc->sc_base.sc_mres[1]; + uint32_t reg; + + /* Dequeue from the direct-connect channel and pool 0, up to 3 frames */ + bus_write_4(regs, QCSP_DQRR_SDQCR, + SDQCR_FC | SDQCR_DP | SDQCR_DCT_PRI_PREC | + (DEF_SDQCR_TOKEN << SDQCR_TOKEN_S) | + DQRR_DQ_SRC_DCP | SDQCR_DQ_SRC_CHAN(0)); + bus_write_4(regs, QCSP_DQRR_VDQCR, 0); + bus_write_4(regs, QCSP_DQRR_PDQCR, 0); + + sc->sc_dqrr.ring = + (struct qman_dqrr_entry *)(sc->sc_base.sc_ce_va + QCSP_DQRR_N(0)); + qman_dqrr_ring_init(&sc->sc_dqrr, &sc->sc_base); + + /* Set DQRR max fill to 15 */ + reg = bus_read_4(regs, QCSP_CFG); + reg |= (0xf << CFG_DQRR_MF_S); + bus_write_4(regs, QCSP_CFG, reg); + + for (int i = 0; i < QMAN_DQRR_COUNT; i++) + __asm __volatile ("dcbi 0,%0" :: "r"(&sc->sc_dqrr.ring[i]) : "memory"); + + return (0); +} int -qman_portals_attach(device_t dev) +qman_portal_attach(device_t dev, int cpu) { - struct dpaa_portals_softc *sc; + struct qman_portal_softc *sc = device_get_softc(dev); + union qman_mc_command *cr; + pcell_t cell; + phandle_t node; + + sc->sc_base.sc_cpu = cpu; + dpaa_portal_alloc_res(dev, cpu); - sc = qp_sc = device_get_softc(dev); - - /* Map bman portal to physical address space */ - if (law_enable(OCP85XX_TGTIF_QMAN, sc->sc_dp_pa, sc->sc_dp_size)) { - qman_portals_detach(dev); + qman_eqcr_init(sc, CFG_EPM_VB1, 0, 0); + qman_dqrr_init(sc); + bus_setup_intr(dev, sc->sc_base.sc_ires, INTR_TYPE_NET | INTR_MPSAFE, + NULL, qman_portal_isr, sc, &sc->sc_base.sc_intr_cookie); + bus_bind_intr(dev, sc->sc_base.sc_ires, cpu); + + node = ofw_bus_get_node(dev); + if (OF_getencprop(node, "cell-index", &cell, sizeof(cell)) <= 0) { + device_printf(dev, "missing 'cell-index' property\n"); return (ENXIO); } - /* Set portal properties for XX_VirtToPhys() */ - XX_PortalSetInfo(dev); + sc->sc_affine_channel = cell; + DPCPU_ID_SET(cpu, qman_affine_portal, dev); + bus_write_4(sc->sc_base.sc_mres[1], QCSP_IER, + QM_PIRQ_EQCI | QM_PIRQ_EQRI | QM_PIRQ_MRI | QM_PIRQ_CSCI | + QM_PIRQ_DQRI); + bus_write_4(sc->sc_base.sc_mres[1], QCSP_ISDR, 0); + + /* Initialize the MC polarity bit, it may not be 0. */ + cr = (union qman_mc_command *)(sc->sc_base.sc_ce_va + QCSP_CR); + sc->sc_mc.polarity = + (cr->common.verb & QMAN_MC_VERB_VBIT) ^ QMAN_MC_VERB_VBIT; + /* TODO: LIODN. Fake it for now */ + + qman_set_sdest(sc->sc_affine_channel, cpu); - bus_attach_children(dev); return (0); } + int -qman_portals_detach(device_t dev) +qman_portal_detach(device_t dev) { - struct dpaa_portals_softc *sc; + struct qman_portal_softc *sc; int i; - qp_sc = NULL; sc = device_get_softc(dev); - for (i = 0; i < ARRAY_SIZE(sc->sc_dp); i++) { - if (sc->sc_dp[i].dp_ph != NULL) { - thread_lock(curthread); - sched_bind(curthread, i); - thread_unlock(curthread); + /* TODO: Unmap TLB regions */ + thread_lock(curthread); + sched_bind(curthread, sc->sc_base.sc_cpu); + thread_unlock(curthread); - QM_PORTAL_Free(sc->sc_dp[i].dp_ph); + if (sc->sc_base.sc_ires != NULL) + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_base.sc_ires); - thread_lock(curthread); - sched_unbind(curthread); - thread_unlock(curthread); - } - - if (sc->sc_dp[i].dp_ires != NULL) { - XX_DeallocIntr((uintptr_t)sc->sc_dp[i].dp_ires); - bus_release_resource(dev, SYS_RES_IRQ, - sc->sc_dp[i].dp_irid, sc->sc_dp[i].dp_ires); - } - } - for (i = 0; i < ARRAY_SIZE(sc->sc_rres); i++) { - if (sc->sc_rres[i] != NULL) + for (i = 0; i < nitems(sc->sc_base.sc_mres); i++) { + if (sc->sc_base.sc_mres[i] != NULL) bus_release_resource(dev, SYS_RES_MEMORY, - sc->sc_rrid[i], - sc->sc_rres[i]); + i, sc->sc_base.sc_mres[i]); } + thread_lock(curthread); + sched_unbind(curthread); + thread_unlock(curthread); + return (0); } -t_Handle -qman_portal_setup(struct qman_softc *qsc) +static void +qman_portal_isr(void *arg) { - struct dpaa_portals_softc *sc; - t_QmPortalParam qpp; - unsigned int cpu; - uintptr_t p; - t_Handle portal; + struct qman_portal_softc *sc = arg; - /* Return NULL if we're not ready or while detach */ - if (qp_sc == NULL) - return (NULL); + qman_portal_loop_rings(sc); +} + +int +qman_portal_fq_enqueue(device_t dev, struct qman_fq *fq, struct dpaa_fd *frame) +{ + struct qman_portal_softc *sc = device_get_softc(dev); + struct qman_eqcr_entry *eqcr; + + /* Get available... */ + eqcr = qman_eqcr_start(&sc->sc_eqcr, &sc->sc_base); + if (eqcr == NULL) + return (EBUSY); + eqcr->fd = *frame; + eqcr->fqid = fq->fqid; + qman_eqcr_commit(&sc->sc_eqcr, QM_EQCR_VERB_CMD_ENQUEUE); + + return (0); +} + +static int +qman_portal_loop_dqrr(struct qman_portal_softc *sc) +{ + struct qman_dqrr_entry *dqrr; + struct qman_dqrr_entry *base; + struct qman_fq *fq; + int ci = bus_read_4(sc->sc_base.sc_mres[1], QCSP_DQRR_CI_CINH) & + DQRR_CI_CI_M; + int pi = bus_read_4(sc->sc_base.sc_mres[1], QCSP_DQRR_PI_CINH) & + DQRR_PI_PI_M; + + base = sc->sc_dqrr.ring; + do { + dqrr = &base[ci]; + dpaa_flush_line(dqrr); + dpaa_touch_line(dqrr); + if ((dqrr->stat & QMAN_DQRR_STAT_HAS_FRAME)) { + fq = qman_fq_from_index(dqrr->fqid); + if (fq != NULL && fq->cb.dqrr != NULL) { + fq->cb.dqrr(sc->sc_base.sc_dev, fq, + &dqrr->fd, fq->cb.ctx); + } + } else + break; + ci = (ci + 1) & DQRR_CI_CI_M; + bus_write_4(sc->sc_base.sc_mres[1], QCSP_DQRR_CI_CINH, ci); + } while (ci != pi); + + return (0); +} + +static void +qman_portal_loop_rings(struct qman_portal_softc *sc) +{ + uint32_t isr; - sc = qp_sc; + isr = bus_read_4(sc->sc_base.sc_mres[1], QCSP_ISR); - sched_pin(); - portal = NULL; - cpu = PCPU_GET(cpuid); + /* Handle DQRR first. */ + if ((isr & QM_PIRQ_DQRI)) { + qman_portal_loop_dqrr(sc); + } + if ((isr & QM_PIRQ_CSCI)) { + } + if ((isr & QM_PIRQ_EQRI)) { + qman_eqcr_update(&sc->sc_eqcr, &sc->sc_base); + } + bus_write_4(sc->sc_base.sc_mres[1], QCSP_ISR, isr); +} - /* Check if portal is ready */ - while (atomic_cmpset_acq_ptr((uintptr_t *)&sc->sc_dp[cpu].dp_ph, - 0, -1) == 0) { - p = atomic_load_acq_ptr((uintptr_t *)&sc->sc_dp[cpu].dp_ph); +/* MC commands */ + +/* Assumes pinned */ +union qman_mc_result * +qman_portal_mc_send_raw(device_t dev, union qman_mc_command *c) +{ + struct qman_portal_softc *sc; + int res_idx; + union qman_mc_result *rr; + union qman_mc_command *cr; + int timeout = 10000; + uint8_t verb; + + sc = device_get_softc(dev); - /* Return if portal is already initialized */ - if (p != 0 && p != -1) { - sched_unpin(); - return ((t_Handle)p); - } + verb = c->common.verb; + c->common.verb = 0; + cr = (union qman_mc_command *)(sc->sc_base.sc_ce_va + QCSP_CR); + dpaa_zero_line(cr); + *cr = *c; + dpaa_lw_barrier(); + cr->common.verb = verb | sc->sc_mc.polarity; + res_idx = (sc->sc_mc.polarity ? 1 : 0); + sc->sc_mc.polarity ^= QMAN_MC_VERB_VBIT; + dpaa_flush_line(cr); + dpaa_touch_line(cr); - /* Not inititialized and "owned" by another thread */ - sched_relinquish(curthread); + rr = (union qman_mc_result *)(sc->sc_base.sc_ce_va + QCSP_RR(res_idx)); + for (; timeout > 0; --timeout) { + dpaa_flush_line(rr); + if (rr->common.verb != 0) + break; } + if (timeout == 0) + return (NULL); + return (rr); +} - /* Map portal registers */ - dpaa_portal_map_registers(sc); +void +qman_portal_static_dequeue_channel(device_t dev, int channel) +{ + struct qman_portal_softc *sc = device_get_softc(dev); + uint32_t reg; - /* Configure and initialize portal */ - qpp.ceBaseAddress = rman_get_bushandle(sc->sc_rres[0]); - qpp.ciBaseAddress = rman_get_bushandle(sc->sc_rres[1]); - qpp.h_Qm = qsc->sc_qh; - qpp.swPortalId = cpu; - qpp.irq = (uintptr_t)sc->sc_dp[cpu].dp_ires; - qpp.fdLiodnOffset = 0; - qpp.f_DfltFrame = qman_received_frame_callback; - qpp.f_RejectedFrame = qman_rejected_frame_callback; - qpp.h_App = qsc; + reg = bus_read_4(sc->sc_base.sc_mres[1], QCSP_DQRR_SDQCR); + reg |= (1 << (15 - (channel - qman_channel_base))); + bus_write_4(sc->sc_base.sc_mres[1], QCSP_DQRR_SDQCR, reg); +} - portal = QM_PORTAL_Config(&qpp); - if (portal == NULL) - goto err; +void +qman_portal_static_dequeue_rm_channel(device_t dev, int channel) +{ + struct qman_portal_softc *sc = device_get_softc(dev); + uint32_t reg; - if (QM_PORTAL_Init(portal) != E_OK) - goto err; + reg = bus_read_4(sc->sc_base.sc_mres[1], QCSP_DQRR_SDQCR); + reg &= ~(1 << (15 - (channel - qman_channel_base))); + bus_write_4(sc->sc_base.sc_mres[1], QCSP_DQRR_SDQCR, reg); +} - if (QM_PORTAL_AddPoolChannel(portal, QMAN_COMMON_POOL_CHANNEL) != E_OK) - goto err; +DB_SHOW_COMMAND(fqid, qman_show_fqid) +{ + union qman_mc_command cmd; + union qman_mc_result *res; + union qman_mc_result save_res; + device_t portal; - atomic_store_rel_ptr((uintptr_t *)&sc->sc_dp[cpu].dp_ph, - (uintptr_t)portal); - sched_unpin(); + if (!have_addr) + return; - return (portal); + bzero(&cmd, sizeof(cmd)); + cmd.query_fq_np.fqid = addr; -err: - if (portal != NULL) - QM_PORTAL_Free(portal); + /* Ensure we have got QMan port initialized */ + portal = DPCPU_GET(qman_affine_portal); + res = qman_portal_mc_send_raw(portal, &cmd); - atomic_store_rel_32((uint32_t *)&sc->sc_dp[cpu].dp_ph, 0); - sched_unpin(); + if (res != NULL) + save_res = *res; - return (NULL); + /* Dump all NP fields */ + if (res != NULL && save_res.query_fq_np.rslt == 0xf0) { + db_printf("FQID: %d\n", (int)addr); + db_printf(" State: %x\n", save_res.query_fq_np.state); + db_printf(" Link: %x\n", save_res.query_fq_np.fqd_link); + db_printf(" ODP_SEQ: %x\n", save_res.query_fq_np.odp_seq); + db_printf(" ORP_NESN: %x\n", save_res.query_fq_np.orp_nesn); + db_printf(" ORP_EA_HSEQ: %x\n", + save_res.query_fq_np.orp_ea_hseq); + db_printf(" ORP_EA_TSEQ: %x\n", + save_res.query_fq_np.orp_ea_tseq); + db_printf(" ORP_EA_HPTR: %x\n", + save_res.query_fq_np.orp_ea_hptr); + db_printf(" ORP_EA_TPTR: %x\n", + save_res.query_fq_np.orp_ea_tptr); + db_printf(" pfdr_hptr: %x\n", save_res.query_fq_np.pfdr_hptr); + db_printf(" pfdr_tptr: %x\n", save_res.query_fq_np.pfdr_tptr); + db_printf(" IS: %x\n", save_res.query_fq_np.is); + db_printf(" ICS_SURP: %x\n", save_res.query_fq_np.ics_surp); + db_printf(" byte_cnt: %x\n", save_res.query_fq_np.byte_cnt); + db_printf(" frm_cnt: %x\n", save_res.query_fq_np.frm_cnt); + db_printf(" ra1_sfdr: %x\n", save_res.query_fq_np.ra1_sfdr); + db_printf(" ra2_sfdr: %x\n", save_res.query_fq_np.ra2_sfdr); + db_printf(" od1_sfdr: %x\n", save_res.query_fq_np.od1_sfdr); + db_printf(" od2_sfdr: %x\n", save_res.query_fq_np.od2_sfdr); + db_printf(" od3_sfdr: %x\n", save_res.query_fq_np.od3_sfdr); + } } diff --git a/sys/dev/dpaa/qman_var.h b/sys/dev/dpaa/qman_var.h new file mode 100644 index 000000000000..8ed36bbb6a35 --- /dev/null +++ b/sys/dev/dpaa/qman_var.h @@ -0,0 +1,167 @@ +/* + * Copyright (c) 2026 Justin Hibbits + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef QMAN_VAR_H +#define QMAN_VAR_H + +#include "dpaa_common.h" +#include "portals.h" + +struct qman_eqcr_entry { + uint8_t verb; + uint8_t dca; + uint16_t seqnum; + uint32_t orp; + uint32_t fqid; + uint32_t tag; + struct dpaa_fd fd; + uint8_t _rsvd[32]; +}; +_Static_assert(sizeof(struct qman_eqcr_entry) == 64, "EQCR entry mis-sized"); +DPAA_RING_DECLARE(qman_eqcr); +DPAA_RING_DECLARE(qman_dqrr); +DPAA_RING_DECLARE(qman_mr); + +union qman_mc_command { + struct { + uint8_t verb; + uint8_t data[63]; + } common; + struct { + uint8_t verb; + uint8_t _rsvd0; + uint16_t we_mask; + uint32_t fqid; /* Only bottom 24 bits allowed */ + uint16_t count; + uint8_t orpc; + uint8_t cgid; + uint16_t fq_ctrl; + uint16_t dest_chan:13; + uint16_t dest_wq:3; + uint16_t ics_cred; + uint16_t td_thresh_oac; + uint32_t context_b; + uint32_t context_a; + uint8_t _rsvd1[32]; + } init_fq; + struct { + uint8_t verb; + uint8_t _rsvd0[3]; + uint32_t fqid; /* Only bottom 24 bits used */ + uint8_t _rsvd1[56]; + } query_fq; + struct { + uint8_t verb; + uint8_t _rsvd0[3]; + uint32_t fqid; + uint8_t _rsvd1[56]; + } query_fq_np; + struct { + uint8_t verb; + uint8_t _rsvd0[3]; + uint32_t fqid; + uint8_t _rsvd1; + uint8_t count; + uint8_t _rsvd2[10]; + uint32_t context_b; + uint8_t _rsvd3[40]; + } alter_fqs; +}; + +union qman_mc_result { + struct { + uint8_t verb; + uint8_t data[63]; + } common; + struct { + uint8_t verb; + uint8_t rslt; + uint8_t _rsvd[62]; + } init_fq; + struct { + uint8_t verb; + uint8_t rslt; + uint8_t _rsvd0[8]; + uint8_t orpc; + uint8_t cgid; + uint16_t fq_ctrl; + uint16_t dest_wq; + uint16_t ics_cred; + uint16_t td_thresh; + uint32_t context_b; + uint32_t context_a; + uint16_t oac; + uint8_t _rsvd1[30]; + } query_fq; + struct { + uint8_t verb; + uint8_t rslt; + uint8_t _rsvd0; + uint8_t state; + uint32_t fqd_link; + uint16_t odp_seq; + uint16_t orp_nesn; + uint16_t orp_ea_hseq; + uint16_t orp_ea_tseq; + uint32_t orp_ea_hptr; + uint32_t orp_ea_tptr; + uint32_t pfdr_hptr; + uint32_t pfdr_tptr; + uint8_t _rsvd1[5]; + uint8_t is; + uint16_t ics_surp; + uint32_t byte_cnt; + uint32_t frm_cnt; + uint32_t _rsvd2; + uint16_t ra1_sfdr; + uint16_t ra2_sfdr; + uint16_t _rsvd3; + uint16_t od1_sfdr; + uint16_t od2_sfdr; + uint16_t od3_sfdr; + } query_fq_np; + struct { + uint8_t verb; + uint8_t rslt; + uint8_t fqs; + uint8_t _rsvd[61]; + } alter_fqs; +}; + +struct qman_mc { + uint8_t polarity; + bool busy; +}; + +struct qman_fq { + uint32_t fqid; + struct qman_cb cb; +}; + +struct qman_portal_softc { + struct dpaa_portal_softc sc_base; + + /* Rings (Enqueue, Dequeue, Message */ + struct qman_eqcr_ring sc_eqcr; + struct qman_dqrr_ring sc_dqrr; + struct qman_mr_ring sc_mr; + struct qman_mc sc_mc; + + int sc_affine_channel; +}; + +struct qman_fq *qman_fq_from_index(uint32_t fqid); + +union qman_mc_result * +qman_portal_mc_send_raw(device_t, union qman_mc_command *); +int qman_portal_fq_enqueue(device_t, struct qman_fq *, struct dpaa_fd *); +void qman_portal_static_dequeue_channel(device_t, int); +void qman_portal_static_dequeue_rm_channel(device_t dev, int channel); + +extern int qman_channel_base; +DPCPU_DECLARE(device_t, qman_affine_portal); + +#endif /* QMAN_VAR_H */ diff --git a/sys/dev/hwpmc/hwpmc_amd.c b/sys/dev/hwpmc/hwpmc_amd.c index 51505bfcff37..299021494716 100644 --- a/sys/dev/hwpmc/hwpmc_amd.c +++ b/sys/dev/hwpmc/hwpmc_amd.c @@ -40,6 +40,7 @@ #include <sys/pmc.h> #include <sys/pmckern.h> #include <sys/smp.h> +#include <sys/sysctl.h> #include <sys/systm.h> #include <machine/cpu.h> @@ -178,6 +179,63 @@ struct amd_cpu { }; static struct amd_cpu **amd_pcpu; +/* Populated by amd_init_policy(); PRECISERETIRE is OR-ed in per-allocation. */ +static uint64_t amd_core_allowed_mask; +static uint64_t amd_l3_allowed_mask; +static uint64_t amd_df_allowed_mask; + +static uint64_t amd_core_extra_mask; +static uint64_t amd_l3_extra_mask; +static uint64_t amd_df_extra_mask; + +SYSCTL_DECL(_kern_hwpmc); + +SYSCTL_U64(_kern_hwpmc, OID_AUTO, amd_core_extra_mask, CTLFLAG_RDTUN, + &amd_core_extra_mask, 0, + "Extra allowed bits in AMD core PMU PERFEVTSEL (override; default 0)"); + +SYSCTL_U64(_kern_hwpmc, OID_AUTO, amd_l3_extra_mask, CTLFLAG_RDTUN, + &amd_l3_extra_mask, 0, + "Extra allowed bits in AMD L3 PMU control (override; default 0)"); + +SYSCTL_U64(_kern_hwpmc, OID_AUTO, amd_df_extra_mask, CTLFLAG_RDTUN, + &amd_df_extra_mask, 0, + "Extra allowed bits in AMD DF PMU control (override; default 0)"); + +static void +amd_init_policy(void) +{ + int family; + + family = CPUID_TO_FAMILY(cpu_id); + + amd_core_allowed_mask = AMD_VALID_BITS; + + amd_l3_allowed_mask = (family <= 0x17) ? + AMD_PMC_L3_FAMILY17_MASK : AMD_PMC_L3_FAMILY19_MASK; + + amd_df_allowed_mask = (family <= 0x19) ? + AMD_PMC_DF_FAMILY17_MASK : AMD_PMC_DF_FAMILY1A_MASK; +} + +static uint64_t +amd_config_mask(enum sub_class subclass, uint64_t caps) +{ + + switch (subclass) { + case PMC_AMD_SUB_CLASS_CORE: + return (amd_core_allowed_mask | amd_core_extra_mask | + (((caps & PMC_CAP_PRECISE) != 0) ? + AMD_PMC_PRECISERETIRE : 0)); + case PMC_AMD_SUB_CLASS_L3_CACHE: + return (amd_l3_allowed_mask | amd_l3_extra_mask); + case PMC_AMD_SUB_CLASS_DATA_FABRIC: + return (amd_df_allowed_mask | amd_df_extra_mask); + default: + return (0); + } +} + /* * Read a PMC value from the MSR. */ @@ -358,9 +416,13 @@ amd_allocate_pmc(int cpu __unused, int ri, struct pmc *pm, return (EINVAL); if (strlen(pmc_cpuid) != 0) { - pm->pm_md.pm_amd.pm_amd_evsel = a->pm_md.pm_amd.pm_amd_config; - PMCDBG2(MDP, ALL, 2,"amd-allocate ri=%d -> config=0x%x", ri, - a->pm_md.pm_amd.pm_amd_config); + config = a->pm_md.pm_amd.pm_amd_config; + if ((config & ~amd_config_mask(amd_pmcdesc[ri].pm_subclass, + caps)) != 0) + return (EINVAL); + pm->pm_md.pm_amd.pm_amd_evsel = config; + PMCDBG2(MDP, ALL, 2, "amd-allocate ri=%d -> config=0x%jx", + ri, (uintmax_t)config); return (0); } @@ -981,6 +1043,8 @@ pmc_amd_initialize(void) pmc_mdep->pmd_npmc += amd_npmcs; + amd_init_policy(); + PMCDBG0(MDP, INI, 0, "amd-initialize"); if (nclasses >= 3) { diff --git a/sys/dev/hwpmc/hwpmc_amd.h b/sys/dev/hwpmc/hwpmc_amd.h index 6d8ab8203942..616d115ecc25 100644 --- a/sys/dev/hwpmc/hwpmc_amd.h +++ b/sys/dev/hwpmc/hwpmc_amd.h @@ -122,6 +122,18 @@ #define AMD_PMC_L3_TO_UNITMASK(x) (((x) << 8) & AMD_PMC_UNITMASK) #define AMD_PMC_L3_TO_EVENTMASK(x) ((x) & 0xFF) +#define AMD_PMC_L3_FAMILY17_MASK \ + (AMD_PMC_ENABLE | AMD_PMC_L3_TO_EVENTMASK(0xff) | \ + AMD_PMC_L3_TO_UNITMASK(0xff) | \ + AMD_PMC_L31_SLICEMASK | AMD_PMC_L31_COREMASK) + +#define AMD_PMC_L3_FAMILY19_MASK \ + (AMD_PMC_ENABLE | AMD_PMC_L3_TO_EVENTMASK(0xff) | \ + AMD_PMC_L3_TO_UNITMASK(0xff) | \ + AMD_PMC_L32_THREADMASK | AMD_PMC_L32_SOURCEMASK | \ + AMD_PMC_L32_ALLCORES | AMD_PMC_L32_ALLSOURCES | \ + AMD_PMC_L32_COREMASK) + #define AMD_PMC_L3_CAPS (PMC_CAP_READ | PMC_CAP_WRITE | \ PMC_CAP_QUALIFIER | PMC_CAP_DOMWIDE) @@ -148,6 +160,16 @@ #define AMD_PMC_DF2_TO_UNITMASK(x) ((((x) & 0xFF) << 8) | \ (((uint64_t)(x) & 0x0F00) << 16)) +#define AMD_PMC_DF_FAMILY17_MASK \ + (AMD_PMC_ENABLE | \ + AMD_PMC_DF1_TO_EVENTMASK(0x3fff) | \ + AMD_PMC_DF1_TO_UNITMASK(0xff)) + +#define AMD_PMC_DF_FAMILY1A_MASK \ + (AMD_PMC_ENABLE | \ + AMD_PMC_DF2_TO_EVENTMASK(0x7fff) | \ + AMD_PMC_DF2_TO_UNITMASK(0xfff)) + #define AMD_NPMCS_K8 4 #define AMD_NPMCS_MAX (AMD_PMC_CORE_MAX + AMD_PMC_L3_MAX + \ AMD_PMC_DF_MAX) diff --git a/sys/dev/hwpmc/hwpmc_ibs.c b/sys/dev/hwpmc/hwpmc_ibs.c index 56903699ac51..8cfe7b2df145 100644 --- a/sys/dev/hwpmc/hwpmc_ibs.c +++ b/sys/dev/hwpmc/hwpmc_ibs.c @@ -36,8 +36,12 @@ #include <sys/pmckern.h> #include <sys/pmclog.h> #include <sys/smp.h> +#include <sys/sysctl.h> #include <sys/systm.h> +#define EXTERR_CATEGORY EXTERR_CAT_HWPMC_IBS +#include <sys/exterrvar.h> + #include <machine/cpu.h> #include <machine/cpufunc.h> #include <machine/md_var.h> @@ -54,6 +58,21 @@ struct ibs_descr { * Globals */ static uint64_t ibs_features; +static uint64_t ibs_fetch_allowed_mask; +static uint64_t ibs_op_allowed_mask; + +static uint64_t ibs_fetch_extra_mask; +static uint64_t ibs_op_extra_mask; + +SYSCTL_DECL(_kern_hwpmc); + +SYSCTL_U64(_kern_hwpmc, OID_AUTO, ibs_fetch_extra_mask, CTLFLAG_RDTUN, + &ibs_fetch_extra_mask, 0, + "Extra allowed bits in the IBS fetch control MSR (override; default 0)"); + +SYSCTL_U64(_kern_hwpmc, OID_AUTO, ibs_op_extra_mask, CTLFLAG_RDTUN, + &ibs_op_extra_mask, 0, + "Extra allowed bits in the IBS op control MSR (override; default 0)"); /* * Per-processor information @@ -68,6 +87,75 @@ struct ibs_cpu { }; static struct ibs_cpu **ibs_pcpu; +static void +ibs_init_policy(void) +{ + + ibs_fetch_allowed_mask = IBS_FETCH_ALLOWED_MASK_BASE; + + ibs_op_allowed_mask = IBS_OP_CTL_MAXCNTBASEMASK; + + if ((ibs_features & CPUID_IBSID_ZEN4IBSEXTENSIONS) != 0) + ibs_fetch_allowed_mask |= IBS_FETCH_CTL_L3MISSONLY; + + if ((ibs_features & CPUID_IBSID_OPCNT) != 0) + ibs_op_allowed_mask |= IBS_OP_CTL_COUNTERCONTROL; + + if ((ibs_features & CPUID_IBSID_OPCNTEXT) != 0) + ibs_op_allowed_mask |= IBS_OP_CTL_MAXCNTEXTMASK; + + if ((ibs_features & CPUID_IBSID_ZEN4IBSEXTENSIONS) != 0) + ibs_op_allowed_mask |= IBS_OP_CTL_L3MISSONLY; +} + +static int +ibs_validate_fetch_config(uint64_t config) +{ + + if ((config & ~(ibs_fetch_allowed_mask | ibs_fetch_extra_mask)) != 0) + return (EINVAL); + + return (0); +} + +static int +ibs_validate_op_config(uint64_t config) +{ + uint64_t allowed_mask; + + allowed_mask = ibs_op_allowed_mask; + + if ((config & IBS_OP_CTL_LATFLTEN) != 0) { + if ((ibs_features & CPUID_IBSID_IBSLOADLATENCYFILT) == 0) + return (EINVAL); + if ((config & IBS_OP_CTL_L3MISSONLY) == 0) + return (EINVAL); + + allowed_mask |= IBS_OP_CTL_LDLATMASK | IBS_OP_CTL_L3MISSONLY; + } + + allowed_mask |= ibs_op_extra_mask; + + if ((config & ~allowed_mask) != 0) + return (EINVAL); + + return (0); +} + +static int +ibs_validate_pmc_config(int ri, uint64_t config) +{ + + switch (ri) { + case IBS_PMC_FETCH: + return (ibs_validate_fetch_config(config)); + case IBS_PMC_OP: + return (ibs_validate_op_config(config)); + default: + return (EINVAL); + } +} + /* * Read a PMC value from the MSR. */ @@ -179,30 +267,37 @@ ibs_allocate_pmc(int cpu __unused, int ri, struct pmc *pm, const struct pmc_op_pmcallocate *a) { uint64_t caps, config; + int error; KASSERT(ri >= 0 && ri < IBS_NPMCS, ("[ibs,%d] illegal row index %d", __LINE__, ri)); /* check class match */ if (a->pm_class != PMC_CLASS_IBS) - return (EINVAL); + return (EXTERROR(EINVAL, "PMC class is not IBS")); if (a->pm_md.pm_ibs.ibs_type != ri) - return (EINVAL); + return (EXTERROR(EINVAL, + "IBS type %ju does not match PMC index %ju", + (uint64_t)a->pm_md.pm_ibs.ibs_type, (uint64_t)ri)); caps = pm->pm_caps; PMCDBG2(MDP, ALL, 1, "ibs-allocate ri=%d caps=0x%x", ri, caps); if ((caps & PMC_CAP_SYSTEM) == 0) - return (EINVAL); + return (EXTERROR(EINVAL, "IBS requires SYSTEM capability")); if (!PMC_IS_SAMPLING_MODE(a->pm_mode)) return (EINVAL); config = a->pm_md.pm_ibs.ibs_ctl; + error = ibs_validate_pmc_config(ri, config); + if (error != 0) + return (error); pm->pm_md.pm_ibs.ibs_ctl = config; - PMCDBG2(MDP, ALL, 2, "ibs-allocate ri=%d -> config=0x%x", ri, config); + PMCDBG2(MDP, ALL, 2, "ibs-allocate ri=%d -> config=0x%jx", ri, + config); return (0); } @@ -356,7 +451,6 @@ pmc_ibs_process_fetch(struct pmc *pm, struct trapframe *tf, uint64_t config) if ((ibs_features & CPUID_IBSID_IBSFETCHCTLEXTD) != 0) { mpd.pl_mpdata[PMC_MPIDX_FETCH_EXTCTL] = rdmsr(IBS_FETCH_EXTCTL); } - mpd.pl_mpdata[PMC_MPIDX_FETCH_CTL] = config; mpd.pl_mpdata[PMC_MPIDX_FETCH_LINADDR] = rdmsr(IBS_FETCH_LINADDR); if ((config & IBS_FETCH_CTL_PHYSADDRVALID) != 0) { mpd.pl_mpdata[PMC_MPIDX_FETCH_PHYSADDR] = @@ -617,10 +711,14 @@ pmc_ibs_initialize(struct pmc_mdep *pmc_mdep, int ncpus) if (cpu_exthigh >= CPUID_IBSID) { do_cpuid(CPUID_IBSID, regs); ibs_features = regs[0]; + if ((ibs_features & CPUID_IBSID_IBSFFV) == 0) + ibs_features = 0; } else { ibs_features = 0; } + ibs_init_policy(); + PMCDBG0(MDP, INI, 0, "ibs-initialize"); return (0); diff --git a/sys/dev/hwpmc/hwpmc_ibs.h b/sys/dev/hwpmc/hwpmc_ibs.h index 2b4e111ba171..433397954d4f 100644 --- a/sys/dev/hwpmc/hwpmc_ibs.h +++ b/sys/dev/hwpmc/hwpmc_ibs.h @@ -100,6 +100,8 @@ #define IBS_FETCH_CTL_TO_LAT(_c) (((_c) >> 32) & 0x0000FFFF) #define IBS_FETCH_COUNT_TO_CTL(_c) (((_c) << 12) & IBS_FETCH_CTL_CURCNTMASK) #define IBS_FETCH_CTL_TO_COUNT(_c) (((_c) & IBS_FETCH_CTL_CURCNTMASK) >> 12) +#define IBS_FETCH_ALLOWED_MASK_BASE (IBS_FETCH_CTL_MAXCNTMASK | \ + IBS_FETCH_CTL_RANDOMIZE) #define IBS_FETCH_LINADDR 0xC0011031 /* Fetch Linear Address */ #define IBS_FETCH_PHYSADDR 0xC0011032 /* Fetch Physical Address */ @@ -118,12 +120,22 @@ #define IBS_OP_CTL_VALID (1ULL << 18) /* Valid */ #define IBS_OP_CTL_ENABLE (1ULL << 17) /* Enable */ #define IBS_OP_CTL_L3MISSONLY (1ULL << 16) /* L3 Miss Filtering */ -#define IBS_OP_CTL_MAXCNTMASK 0x07F0FFFFULL +#define IBS_OP_CTL_MAXCNTMASK 0x07F0FFFFULL /* Max Count */ +#define IBS_OP_CTL_MAXCNTEXTMASK 0x07F00000ULL /* Max Count Extended */ +#define IBS_OP_CTL_MAXCNTBASEMASK (IBS_OP_CTL_MAXCNTMASK & \ + ~IBS_OP_CTL_MAXCNTEXTMASK) /* Max Count Base */ #define IBS_OP_CTL_CURCNTMASK 0x07FFFFFF00000000ULL +#define IBS_OP_CTL_LDLATTRSHMASK (0xFULL << 59) /* Load Lat Threshold */ +#define IBS_OP_CTL_LDLATMASK (IBS_OP_CTL_LATFLTEN | \ + IBS_OP_CTL_LDLATTRSHMASK) /* Load Lat Combined */ -#define IBS_OP_CTL_LDLAT_TO_CTL(_c) ((((ldlat) >> 7) - 1) << 59) -#define IBS_OP_INTERVAL_TO_CTL(_c) ((((_c) >> 4) & 0x0000FFFFULL) | ((_c) & 0x07F00000)) -#define IBS_OP_CTL_TO_INTERVAL(_c) ((((_c) & 0x0000FFFFULL) << 4) | ((_c) & 0x07F00000)) +#define IBS_OP_CTL_LDLAT_TO_CTL(_c) (((((_c) >> 7) - 1) & 0xFULL) << 59) +#define IBS_OP_INTERVAL_TO_CTL(_c) \ + ((((_c) >> 4) & IBS_OP_CTL_MAXCNTBASEMASK) | \ + ((_c) & IBS_OP_CTL_MAXCNTEXTMASK)) +#define IBS_OP_CTL_TO_INTERVAL(_c) \ + ((((_c) & IBS_OP_CTL_MAXCNTBASEMASK) << 4) | \ + ((_c) & IBS_OP_CTL_MAXCNTEXTMASK)) #define IBS_OP_COUNT_TO_CTL(_c) (((_c) << 32) & IBS_OP_CTL_CURCNTMASK) #define IBS_OP_CTL_TO_COUNT(_c) (((_c) & IBS_OP_CTL_CURCNTMASK) >> 32) diff --git a/sys/dev/ichsmb/ichsmb.c b/sys/dev/ichsmb/ichsmb.c index e40a8a8a3886..0df757d9cc0e 100644 --- a/sys/dev/ichsmb/ichsmb.c +++ b/sys/dev/ichsmb/ichsmb.c @@ -395,6 +395,15 @@ ichsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) sc->block_write = true; mtx_lock(&sc->mutex); + /* + * We don't expect the block buffer to be enabled. However, BIOS code + * might enable it and doesn't restore it at any time, so we should + * ensure it's disabled before sending an SMBus command. + */ + if (sc->features & ICHSMB_FEATURE_BLOCK_BUFFER) { + bus_write_1(sc->io_res, ICH_AUX_CNT, + bus_read_1(sc->io_res, ICH_AUX_CNT) & ~ICH_AUX_CNT_E32B); + } sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK; bus_write_1(sc->io_res, ICH_XMIT_SLVA, slave | ICH_XMIT_SLVA_WRITE); @@ -424,6 +433,15 @@ ichsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) sc->block_write = false; mtx_lock(&sc->mutex); + /* + * We don't expect the block buffer to be enabled. However, BIOS code + * might enable it and doesn't restore it at any time, so we should + * ensure it's disabled before sending an SMBus command. + */ + if (sc->features & ICHSMB_FEATURE_BLOCK_BUFFER) { + bus_write_1(sc->io_res, ICH_AUX_CNT, + bus_read_1(sc->io_res, ICH_AUX_CNT) & ~ICH_AUX_CNT_E32B); + } sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK; bus_write_1(sc->io_res, ICH_XMIT_SLVA, slave | ICH_XMIT_SLVA_READ); diff --git a/sys/dev/ichsmb/ichsmb_pci.c b/sys/dev/ichsmb/ichsmb_pci.c index 7d6d94dbb4a4..7f9409e4452c 100644 --- a/sys/dev/ichsmb/ichsmb_pci.c +++ b/sys/dev/ichsmb/ichsmb_pci.c @@ -110,7 +110,8 @@ #define ID_ELKHARTLAKE 0x4b23 #define ID_GEMINILAKE 0x31d4 #define ID_CEDARFORK 0x18df -#define ID_ICELAKE 0x34a3 +#define ID_ICELAKELP 0x34a3 +#define ID_ICELAKEN 0x38a3 #define ID_ALDERLAKE 0x7aa3 #define ID_ALDERLAKE2 0x51a3 #define ID_ALDERLAKE3 0x54a3 @@ -129,106 +130,155 @@ static const struct pci_device_table ichsmb_devices[] = { { PCI_DEV(PCI_VENDOR_INTEL, ID_82801CA), PCI_DESCR("Intel 82801CA (ICH3) SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_82801DC), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel 82801DC (ICH4) SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_82801EB), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel 82801EB (ICH5) SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_82801FB), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel 82801FB (ICH6) SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_82801GB), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel 82801GB (ICH7) SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_82801H), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel 82801H (ICH8) SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_82801I), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel 82801I (ICH9) SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_82801GB), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel 82801GB (ICH7) SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_82801H), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel 82801H (ICH8) SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_82801I), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel 82801I (ICH9) SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_EP80579), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel EP80579 SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_82801JI), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel 82801JI (ICH10) SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_82801JD), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel 82801JD (ICH10) SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_PCH), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel PCH SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_6300ESB), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel 6300ESB (ICH) SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_631xESB), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel 631xESB/6321ESB (ESB2) SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_DH89XXCC), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel DH89xxCC SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_PATSBURG), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Patsburg SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_CPT), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Cougar Point SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_PPT), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Panther Point SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_AVOTON), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Avoton SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_LPT), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Lynx Point SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_LPTLP), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Lynx Point-LP SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_WCPT), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Wildcat Point SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_WCPTLP), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Wildcat Point-LP SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_BAYTRAIL), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Baytrail SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_BRASWELL), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Braswell SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_COLETOCRK), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Coleto Creek SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_WELLSBURG), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Wellsburg SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_SRPT), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Sunrise Point-H SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_SRPTLP), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Sunrise Point-LP SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_DENVERTON), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Denverton SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_BROXTON), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Broxton SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_LEWISBURG), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Lewisburg SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_LEWISBURG2), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Lewisburg SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_KABYLAKE), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Kaby Lake SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_CANNONLAKE), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Cannon Lake SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_COMETLAKE), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Comet Lake SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_COMETLAKE2), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Comet Lake SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_TIGERLAKE), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Tiger Lake SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_TIGERLAKE2), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Tiger Lake SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_ELKHARTLAKE), PCI_DESCR("Intel Elkhart Lake SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_GEMINILAKE), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Gemini Lake SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_CEDARFORK), PCI_DESCR("Intel Cedar Fork SMBus controller") }, - { PCI_DEV(PCI_VENDOR_INTEL, ID_ICELAKE), - PCI_DESCR("Intel Ice Lake SMBus controller") }, + { PCI_DEV(PCI_VENDOR_INTEL, ID_ICELAKELP), + PCI_DESCR("Intel Ice Lake-LP SMBus controller") }, + { PCI_DEV(PCI_VENDOR_INTEL, ID_ICELAKEN), + PCI_DESCR("Intel Ice Lake-N SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_ALDERLAKE), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Alder Lake SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_ALDERLAKE2), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Alder Lake SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_ALDERLAKE3), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Alder Lake SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_RAPTORLAKE), PCI_DESCR("Intel Raptor Lake SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_METEORLAKE), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Meteor Lake SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_METEORLAKE2), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Meteor Lake SMBus controller") }, { PCI_DEV(PCI_VENDOR_INTEL, ID_METEORLAKE3), + .driver_data = (uintptr_t)ICHSMB_FEATURE_BLOCK_BUFFER, PCI_DESCR("Intel Meteor Lake SMBus controller") }, }; @@ -288,6 +338,7 @@ ichsmb_pci_probe(device_t dev) static int ichsmb_pci_attach(device_t dev) { + const struct pci_device_table *tbl; const sc_p sc = device_get_softc(dev); int error; @@ -296,6 +347,12 @@ ichsmb_pci_attach(device_t dev) sc->ich_cmd = -1; sc->dev = dev; + tbl = PCI_MATCH(dev, ichsmb_devices); + if (tbl == NULL) + return (ENXIO); + + sc->features = (uint32_t)tbl->driver_data; + /* Allocate an I/O range */ sc->io_rid = ICH_SMB_BASE; sc->io_res = bus_alloc_resource_anywhere(dev, SYS_RES_IOPORT, diff --git a/sys/dev/ichsmb/ichsmb_reg.h b/sys/dev/ichsmb/ichsmb_reg.h index 78e398a556ef..be3b9e4a899d 100644 --- a/sys/dev/ichsmb/ichsmb_reg.h +++ b/sys/dev/ichsmb/ichsmb_reg.h @@ -84,6 +84,9 @@ #define ICH_D0 0x05 /* host data 0 */ #define ICH_D1 0x06 /* host data 1 */ #define ICH_BLOCK_DB 0x07 /* block data byte */ +#define ICH_AUX_CNT 0x0d /* auxiliary control */ +#define ICH_AUX_CNT_E32B 0x02 /* enable 32 byte buffer */ +#define ICH_AUX_CNT_AAC 0x01 /* automatically append crc */ #endif /* _DEV_ICHSMB_ICHSMB_REG_H_ */ diff --git a/sys/dev/ichsmb/ichsmb_var.h b/sys/dev/ichsmb/ichsmb_var.h index 8aeaf403781b..f16a40be9777 100644 --- a/sys/dev/ichsmb/ichsmb_var.h +++ b/sys/dev/ichsmb/ichsmb_var.h @@ -41,6 +41,8 @@ #include "smbus_if.h" +#define ICHSMB_FEATURE_BLOCK_BUFFER 0x01 /* supports 32 byte block buffer */ + /* Per-device private info */ struct ichsmb_softc { @@ -52,6 +54,7 @@ struct ichsmb_softc { struct resource *irq_res; /* interrupt resource */ int irq_rid; /* interrupt bus id */ void *irq_handle; /* handle for interrupt code */ + uint32_t features; /* supported device features */ /* Device state */ int ich_cmd; /* ich command, or -1 */ diff --git a/sys/dev/iicbus/mux/iicmux.c b/sys/dev/iicbus/mux/iicmux.c index 96164719577c..32b7405ebe19 100644 --- a/sys/dev/iicbus/mux/iicmux.c +++ b/sys/dev/iicbus/mux/iicmux.c @@ -62,7 +62,7 @@ iicmux_callback(device_t dev, int index, caddr_t data) /* If it's not one of the operations we know about, bail early. */ if (index != IIC_REQUEST_BUS && index != IIC_RELEASE_BUS) - return (iic2errno(EOPNOTSUPP)); + return (errno2iic(EOPNOTSUPP)); /* * Ensure that the data passed to us includes the device_t of the child @@ -72,12 +72,12 @@ iicmux_callback(device_t dev, int index, caddr_t data) */ rd = (struct iic_reqbus_data *)data; if (!(rd->flags & IIC_REQBUS_DEV)) - return (iic2errno(EINVAL)); + return (errno2iic(EINVAL)); for (i = 0; i <= sc->maxbus && sc->childdevs[i] != rd->bus; ++i) continue; if (i > sc->maxbus) - return (iic2errno(ENOENT)); + return (errno2iic(ENOENT)); /* * If the operation is a release it "cannot fail". Idle the downstream diff --git a/sys/dev/iicbus/rtc/rs5c372a.c b/sys/dev/iicbus/rtc/rs5c372a.c new file mode 100644 index 000000000000..1511025801f5 --- /dev/null +++ b/sys/dev/iicbus/rtc/rs5c372a.c @@ -0,0 +1,162 @@ +/* + * Copyright (c) 2026 Justin Hibbits + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/clock.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/module.h> + +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> + +#include <dev/iicbus/iiconf.h> +#include <dev/iicbus/iicbus.h> + +#include "clock_if.h" +#include "iicbus_if.h" + +/* + * Driver for the Richo rs5c372a RTC. The chip itself includes 2 alarm clocks + * in addition to the clock component, but this driver offers only the RTC + * component. + * + * Like many other RTCs, this reports the date and time in BCD. + * + * The `Hour' register uses bit 5 in a dual role: In 24-hour time, it's a part + * of the first digit (0, 1, 2). In 12-hour time it denotes PM, so 12PM is + * reported as 0x32, 1PM is 0x21, etc. + */ +#define RS5C372_REG_SEC 0x0 +#define RS5C372_REG_MIN 0x1 +#define RS5C372_REG_HOUR 0x2 +#define HOUR_HR_M 0x1f +#define HOUR_PM 0x20 +#define RS5C372_REG_DOW 0x3 +#define RS5C372_REG_DAY 0x4 +#define RS5C372_REG_MON 0x5 +#define RS5C372_REG_YEAR 0x6 +#define RS5C372_REG_CTRL1 0xe +#define RS5C372_REG_CTRL2 0xf +#define CTRL_PM 0x20 + +static struct ofw_compat_data compat_data[] = { + { "ricoh,rs5c372a", 1 }, + { NULL, 0 } +}; + +static int +rs5c372a_gettime(device_t dev, struct timespec *ts) +{ + struct bcd_clocktime ct = {}; + uint8_t clock_regs[7]; + int err; + uint8_t ctrl2; + bool is_12hr = true; + + err = iicdev_readfrom(dev, RS5C372_REG_CTRL2, &ctrl2, + sizeof(ctrl2), IIC_WAIT); + if (err != 0) + return (err); + err = iicdev_readfrom(dev, RS5C372_REG_SEC, clock_regs, + sizeof(clock_regs), IIC_WAIT); + if (err != 0) + return (err); + + if (ctrl2 & CTRL_PM) + is_12hr = false; + ct.sec = clock_regs[RS5C372_REG_SEC]; + ct.min = clock_regs[RS5C372_REG_MIN]; + ct.hour = clock_regs[RS5C372_REG_HOUR]; + ct.dow = clock_regs[RS5C372_REG_DOW]; + ct.day = clock_regs[RS5C372_REG_DAY]; + ct.mon = clock_regs[RS5C372_REG_MON]; + ct.year = clock_regs[RS5C372_REG_YEAR]; + + if (is_12hr) { + ct.ispm = ct.hour & HOUR_PM; + ct.hour &= HOUR_HR_M; + } + clock_bcd_to_ts(&ct, ts, ct.ispm); + + return (0); +} + +static int +rs5c372a_settime(device_t dev, struct timespec *ts) +{ + struct bcd_clocktime ct; + uint8_t clock_regs[7]; + uint8_t ctrl2; + int err; + bool is_12hr = true; + + err = iicdev_readfrom(dev, RS5C372_REG_CTRL2, &ctrl2, + sizeof(ctrl2), IIC_WAIT); + if (err != 0) + return (err); + if (ctrl2 & CTRL_PM) + is_12hr = false; + clock_ts_to_bcd(ts, &ct, is_12hr); + clock_regs[RS5C372_REG_SEC] = ct.sec; + clock_regs[RS5C372_REG_MIN] = ct.min; + clock_regs[RS5C372_REG_HOUR] = ct.hour; + clock_regs[RS5C372_REG_DAY] = ct.day; + clock_regs[RS5C372_REG_DOW] = ct.dow; + clock_regs[RS5C372_REG_MON] = ct.mon; + clock_regs[RS5C372_REG_YEAR] = ct.year & 0xff; + + if (is_12hr) { + if (ct.ispm) + clock_regs[RS5C372_REG_HOUR] |= HOUR_PM; + } + + err = iicdev_writeto(dev, RS5C372_REG_SEC, clock_regs, + sizeof(clock_regs), IIC_WAIT); + + return (err); +} + +static int +rs5c372a_probe(device_t dev) +{ + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "Richo RS5C372A RTC"); + + return (BUS_PROBE_DEFAULT); +} + +static int +rs5c372a_attach(device_t dev) +{ + + /* Register with 1s resolution */ + clock_register(dev, 1000000); + clock_schedule(dev, 1); + return (0); +} + +static device_method_t rs5c372a_methods[] = { + /* Device methods */ + DEVMETHOD(device_probe, rs5c372a_probe), + DEVMETHOD(device_attach, rs5c372a_attach), + + /* Clock methods */ + DEVMETHOD(clock_gettime, rs5c372a_gettime), + DEVMETHOD(clock_settime, rs5c372a_settime), + DEVMETHOD_END +}; + + +DEFINE_CLASS_0(rs5c372a, rs5c372a_driver, rs5c372a_methods, 0); +DRIVER_MODULE(rs5c372a, iicbus, rs5c372a_driver, NULL, NULL); +MODULE_VERSION(rs5c372a, 1); +MODULE_DEPEND(rs5c372a, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); +IICBUS_FDT_PNP_INFO(compat_data); diff --git a/sys/dev/mfi/mfi.c b/sys/dev/mfi/mfi.c index 6f94e4203f1a..767d5ba0902c 100644 --- a/sys/dev/mfi/mfi.c +++ b/sys/dev/mfi/mfi.c @@ -371,9 +371,6 @@ mfi_attach(struct mfi_softc *sc) if (sc == NULL) return EINVAL; - device_printf(sc->mfi_dev, "LSI MegaRAID SAS driver version: %s\n", - MEGASAS_VERSION); - mtx_init(&sc->mfi_io_lock, "MFI I/O lock", NULL, MTX_DEF); sx_init(&sc->mfi_config_lock, "MFI config"); TAILQ_INIT(&sc->mfi_ld_tqh); @@ -764,6 +761,10 @@ mfi_attach(struct mfi_softc *sc) sc->mfi_cdev, "%s", "megaraid_sas_ioctl_node"); if (sc->mfi_cdev != NULL) sc->mfi_cdev->si_drv1 = sc; + SYSCTL_ADD_STRING(device_get_sysctl_ctx(sc->mfi_dev), + SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)), + OID_AUTO, "driver_version", CTLFLAG_RD, MEGASAS_VERSION, + strlen(MEGASAS_VERSION), "driver version"); SYSCTL_ADD_INT(device_get_sysctl_ctx(sc->mfi_dev), SYSCTL_CHILDREN(device_get_sysctl_tree(sc->mfi_dev)), OID_AUTO, "delete_busy_volumes", CTLFLAG_RW, diff --git a/sys/dev/mii/miidevs b/sys/dev/mii/miidevs index ca7e78a1cdd5..89d8e54a1843 100644 --- a/sys/dev/mii/miidevs +++ b/sys/dev/mii/miidevs @@ -72,7 +72,7 @@ oui RDC 0x00d02d RDC Semiconductor oui REALTEK 0x00e04c Realtek Semicondctor oui SEEQ 0x00a07d Seeq Technology oui SIS 0x00e006 Silicon Integrated Systems -oui SMC 0x00800f SMC +oui SMSC 0x00800f Microchip (formerly SMSC) oui TI 0x080028 Texas Instruments oui TSC 0x00c039 TDK Semiconductor oui VITESSE 0x0001c1 Vitesse Semiconductor @@ -361,6 +361,6 @@ model xxVITESSE VSC8514 0x0027 Vitesse VSC8514 10/100/1000TX PHY /* XaQti Corp. PHYs */ model xxXAQTI XMACII 0x0000 XaQti Corp. XMAC II gigabit interface -/* SMC */ -model SMC LAN8710A 0x000F SMC LAN8710A 10/100 interface -model SMC LAN8700 0x000C SMC LAN8700 10/100 interface +/* Microchip (formerly SMSC) */ +model SMSC LAN8710A 0x000F Microchip LAN8710A 10/100 interface +model SMSC LAN8700 0x000C Microchip LAN8700 10/100 interface diff --git a/sys/dev/mii/smscphy.c b/sys/dev/mii/smscphy.c index 4e0d3cd3e18e..d578242f5a61 100644 --- a/sys/dev/mii/smscphy.c +++ b/sys/dev/mii/smscphy.c @@ -74,8 +74,8 @@ static driver_t smscphy_driver = { DRIVER_MODULE(smscphy, miibus, smscphy_driver, 0, 0); static const struct mii_phydesc smscphys[] = { - MII_PHY_DESC(SMC, LAN8710A), - MII_PHY_DESC(SMC, LAN8700), + MII_PHY_DESC(SMSC, LAN8710A), + MII_PHY_DESC(SMSC, LAN8700), MII_PHY_END }; diff --git a/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c b/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c index 89d2010656c5..b6a9a0c01d09 100644 --- a/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c +++ b/sys/dev/mlx5/mlx5_en/mlx5_en_hw_tls_rx.c @@ -596,14 +596,21 @@ mlx5e_tls_rx_work(struct work_struct *work) if (ptag->flow_rule != NULL) mlx5e_accel_fs_del_inpcb(ptag->flow_rule); + /* + * Destroy TIR before DEK. DESTROY_TIR for a TLS- + * enabled TIR issues a TRA RX fence that drains all + * in-flight packets from the crypto pipeline. If the + * DEK were destroyed first, packets still in flight + * would hit a TPT encryption error (vendor syndrome + * 0x55) because the key they reference is already gone. + */ + if (ptag->tirn != 0) + mlx5_tls_close_tir(priv->mdev, ptag->tirn); + /* try to destroy DEK context by ID */ if (ptag->dek_index_ok) mlx5_encryption_key_destroy(priv->mdev, ptag->dek_index); - /* try to destroy TIR context by ID */ - if (ptag->tirn != 0) - mlx5_tls_close_tir(priv->mdev, ptag->tirn); - /* free tag */ mlx5e_tls_rx_tag_zfree(ptag); break; diff --git a/sys/dev/mrsas/mrsas.c b/sys/dev/mrsas/mrsas.c index 379fcbcb19ca..e8f43ad52ed8 100644 --- a/sys/dev/mrsas/mrsas.c +++ b/sys/dev/mrsas/mrsas.c @@ -824,9 +824,6 @@ mrsas_attach(device_t dev) struct mrsas_softc *sc = device_get_softc(dev); uint32_t cmd, error; - device_printf(dev, "AVAGO MegaRAID SAS driver version: %s\n", - MRSAS_VERSION); - memset(sc, 0, sizeof(struct mrsas_softc)); /* Look up our softc and initialize its fields. */ diff --git a/sys/dev/netmap/netmap.c b/sys/dev/netmap/netmap.c index f531151fb656..6f79c2c45b39 100644 --- a/sys/dev/netmap/netmap.c +++ b/sys/dev/netmap/netmap.c @@ -3503,6 +3503,7 @@ nmreq_copyin(struct nmreq_header *hdr, int nr_body_is_user) /* check optsz and nro_size to avoid for possible integer overflows of rqsz */ if ((optsz > NETMAP_REQ_MAXSIZE) || (opt->nro_size > NETMAP_REQ_MAXSIZE) || (rqsz + optsz > NETMAP_REQ_MAXSIZE) + || (p - ker + optsz > bufsz) || (optsz > 0 && rqsz + optsz <= rqsz)) { error = EMSGSIZE; goto out_restore; diff --git a/sys/dev/rtsx/rtsx.c b/sys/dev/rtsx/rtsx.c index aed0bd6c8b8c..958eb08311c4 100644 --- a/sys/dev/rtsx/rtsx.c +++ b/sys/dev/rtsx/rtsx.c @@ -139,7 +139,7 @@ struct rtsx_softc { uint64_t rtsx_write_count; /* count of write operations */ bool rtsx_discovery_mode; /* are we in discovery mode? */ bool rtsx_tuning_mode; /* are we tuning */ - bool rtsx_double_clk; /* double clock freqency */ + bool rtsx_double_clk; /* double clock frequency */ bool rtsx_vpclk; /* voltage at Pulse-width Modulation(PWM) clock? */ uint8_t rtsx_ssc_depth; /* Spread spectrum clocking depth */ uint8_t rtsx_card_drive_sel; /* value for RTSX_CARD_DRIVE_SEL */ @@ -2837,7 +2837,7 @@ rtsx_xfer_start(struct rtsx_softc *sc) } else { dma_dir = RTSX_DMA_DIR_TO_CARD; /* - * Use transfer mode AUTO_WRITE3, wich assumes we've already + * Use transfer mode AUTO_WRITE3, which assumes we've already * sent the write command and gotten the response, and will * send CMD 12 manually after writing. */ diff --git a/sys/dev/smartpqi/smartpqi_cam.c b/sys/dev/smartpqi/smartpqi_cam.c index 690b38c9f855..6ded8aa97e39 100644 --- a/sys/dev/smartpqi/smartpqi_cam.c +++ b/sys/dev/smartpqi/smartpqi_cam.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2025 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2026 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -1300,7 +1300,7 @@ register_sim(struct pqisrc_softstate *softs, int card_index) csa.callback_arg = softs; xpt_action((union ccb *)&csa); if (csa.ccb_h.status != CAM_REQ_CMP) { - DBG_ERR("Unable to register smartpqi_aysnc handler: %d!\n", + DBG_ERR("Unable to register smartpqi_async handler: %d!\n", csa.ccb_h.status); } diff --git a/sys/dev/smartpqi/smartpqi_defines.h b/sys/dev/smartpqi/smartpqi_defines.h index 0277abd3e318..c4084f069588 100644 --- a/sys/dev/smartpqi/smartpqi_defines.h +++ b/sys/dev/smartpqi/smartpqi_defines.h @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2025 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2026 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -944,12 +944,12 @@ typedef uint8_t *passthru_buf_type_t; #define PQISRC_DRIVER_MAJOR __FreeBSD__ #if __FreeBSD__ <= 14 -#define PQISRC_DRIVER_MINOR 4690 +#define PQISRC_DRIVER_MINOR 4691 #else #define PQISRC_DRIVER_MINOR 2 #endif -#define PQISRC_DRIVER_RELEASE 0 -#define PQISRC_DRIVER_REVISION 2008 +#define PQISRC_DRIVER_RELEASE 1 +#define PQISRC_DRIVER_REVISION 2000 #define STR(s) # s #define PQISRC_VERSION(a, b, c, d) STR(a.b.c-d) diff --git a/sys/dev/smartpqi/smartpqi_discovery.c b/sys/dev/smartpqi/smartpqi_discovery.c index a7de5a149810..8682e6cabd7e 100644 --- a/sys/dev/smartpqi/smartpqi_discovery.c +++ b/sys/dev/smartpqi/smartpqi_discovery.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2025 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2026 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -155,7 +155,7 @@ pqisrc_remove_target_bit(pqisrc_softstate_t *softs, int target) softs->bit_map.bit_vector[target] = SLOT_AVAILABLE; } -/* Use bit map to find availible targets */ +/* Use bit map to find available targets */ int pqisrc_find_avail_target(pqisrc_softstate_t *softs) { @@ -1423,7 +1423,11 @@ pqisrc_add_device(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) if(device->expose_device) { pqisrc_init_device_active_io(softs, device); - /* TBD: Call OS upper layer function to add the device entry */ + device_printf(softs->os_specific.pqi_dev, + "device added: vendor=%s model=%s B%d:T%d:L%d type=%s\n", + device->vendor, device->model, + device->bus, device->target, device->lun, + device->is_physical_device ? "physical" : "logical"); os_add_device(softs,device); } DBG_FUNC("OUT\n"); @@ -1451,6 +1455,11 @@ pqisrc_remove_device(pqisrc_softstate_t *softs, pqi_scsi_dev_t *device) } /* Wait for device outstanding Io's */ pqisrc_wait_for_device_commands_to_complete(softs, device); + device_printf(softs->os_specific.pqi_dev, + "device removed: vendor=%s model=%s B%d:T%d:L%d type=%s\n", + device->vendor, device->model, + device->bus, device->target, device->lun, + device->is_physical_device ? "physical" : "logical"); /* Call OS upper layer function to remove the exposed device entry */ os_remove_device(softs,device); DBG_FUNC("OUT\n"); @@ -1674,10 +1683,14 @@ pqisrc_update_device_list(pqisrc_softstate_t *softs, case DEVICE_NOT_FOUND: /* Device not found in existing list */ device->new_device = true; + DBG_DISC("new device found B%d:T%d:L%d\n", + device->bus, device->target, device->lun); break; case DEVICE_CHANGED: /* Actual device gone need to add device to list*/ device->new_device = true; + DBG_DISC("device changed B%d:T%d:L%d\n", + device->bus, device->target, device->lun); break; case DEVICE_IN_REMOVE: /*Older device with same target/lun is in removal stage*/ @@ -1686,6 +1699,8 @@ pqisrc_update_device_list(pqisrc_softstate_t *softs, * free call*/ device->new_device = false; same_device->schedule_rescan = true; + DBG_DISC("device in removal B%d:T%d:L%d, scheduling rescan\n", + device->bus, device->target, device->lun); break; default: break; diff --git a/sys/dev/smartpqi/smartpqi_event.c b/sys/dev/smartpqi/smartpqi_event.c index 77a70f9fb031..c3c27c9e1c0b 100644 --- a/sys/dev/smartpqi/smartpqi_event.c +++ b/sys/dev/smartpqi/smartpqi_event.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2025 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2026 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -204,6 +204,17 @@ pqisrc_process_event_intr_src(pqisrc_softstate_t *softs,int obq_id) } if (event_index >= 0) { + static const char *event_names[] = { + [PQI_EVENT_HOTPLUG] = "hotplug", + [PQI_EVENT_HARDWARE] = "hardware", + [PQI_EVENT_PHYSICAL_DEVICE] = "physical device", + [PQI_EVENT_LOGICAL_DEVICE] = "logical device", + [PQI_EVENT_AIO_STATE_CHANGE] = "AIO state change", + [PQI_EVENT_AIO_CONFIG_CHANGE] = "AIO config change", + }; + device_printf(softs->os_specific.pqi_dev, + "event: %s (type=0x%x)\n", + event_names[event_index], response.event_type); if(response.request_acknowledge) { pending_event = &softs->pending_events[event_index]; pending_event->pending = true; @@ -385,7 +396,7 @@ pqisrc_report_event_config(pqisrc_softstate_t *softs) pqi_event_config_request_t request; pqi_event_config_t *event_config_p ; dma_mem_t buf_report_event ; - /*bytes to be allocaed for report event config data-in buffer */ + /*bytes to be allocated for report event config data-in buffer */ uint32_t alloc_size = sizeof(pqi_event_config_t) ; memset(&request, 0 , sizeof(request)); @@ -446,7 +457,7 @@ pqisrc_set_event_config(pqisrc_softstate_t *softs) pqi_event_config_request_t request; pqi_event_config_t *event_config_p; dma_mem_t buf_set_event; - /*bytes to be allocaed for set event config data-out buffer */ + /*bytes to be allocated for set event config data-out buffer */ uint32_t alloc_size = sizeof(pqi_event_config_t); memset(&request, 0 , sizeof(request)); diff --git a/sys/dev/smartpqi/smartpqi_main.c b/sys/dev/smartpqi/smartpqi_main.c index 1f006939bf7c..fbfbcc962f35 100644 --- a/sys/dev/smartpqi/smartpqi_main.c +++ b/sys/dev/smartpqi/smartpqi_main.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2025 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2026 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -427,6 +427,16 @@ smartpqi_attach(device_t dev) goto out; } + /* Register sysctl for runtime debug_level changes */ + { + struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev); + struct sysctl_oid *tree = device_get_sysctl_tree(dev); + + SYSCTL_ADD_ULONG(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, + "debug_level", CTLFLAG_RW, &logging_level, + "Debug logging bitmask"); + } + goto out; dma_out: diff --git a/sys/dev/smartpqi/smartpqi_misc.c b/sys/dev/smartpqi/smartpqi_misc.c index 6db0d80ed993..fd0b907aa252 100644 --- a/sys/dev/smartpqi/smartpqi_misc.c +++ b/sys/dev/smartpqi/smartpqi_misc.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2025 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2026 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -252,7 +252,7 @@ bsd_set_hint_scatter_gather_config(struct pqisrc_softstate *softs) DBG_FUNC("IN\n"); - /* At least > 16 sg's required to wotk hint correctly. + /* At least > 16 sg's required to work hint correctly. * Default the sg count set by driver/controller. */ if ((!softs->hint.sg_segments) || (softs->hint.sg_segments > diff --git a/sys/dev/smartpqi/smartpqi_queue.c b/sys/dev/smartpqi/smartpqi_queue.c index e8a467531aa4..679d956f6f36 100644 --- a/sys/dev/smartpqi/smartpqi_queue.c +++ b/sys/dev/smartpqi/smartpqi_queue.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2025 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2026 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -729,7 +729,7 @@ pqisrc_create_op_ibq(pqisrc_softstate_t *softs, op_ib_q->pi_register_offset); } else { int i = 0; - DBG_WARN("Error Status Decsriptors\n"); + DBG_WARN("Error Status Descriptors\n"); for (i = 0; i < 4; i++) DBG_WARN(" %x\n",admin_resp.resp_type.create_op_iq.status_desc[i]); } diff --git a/sys/dev/smartpqi/smartpqi_request.c b/sys/dev/smartpqi/smartpqi_request.c index c5f8ac3c41ba..655660615797 100644 --- a/sys/dev/smartpqi/smartpqi_request.c +++ b/sys/dev/smartpqi/smartpqi_request.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2025 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2026 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -1998,7 +1998,7 @@ pqisrc_send_raid_tmf(pqisrc_softstate_t *softs, pqi_scsi_dev_t const *devp, if (softs->timeout_in_tmf && tmf_type == SOP_TASK_MANAGEMENT_LUN_RESET) { - /* OS_TMF_TIMEOUT_SEC - 1 to accomodate driver processing */ + /* OS_TMF_TIMEOUT_SEC - 1 to accommodate driver processing */ tmf_req.timeout_in_sec = OS_TMF_TIMEOUT_SEC - 1; } diff --git a/sys/dev/smartpqi/smartpqi_response.c b/sys/dev/smartpqi/smartpqi_response.c index 38695860e520..1ae74a5b95ff 100644 --- a/sys/dev/smartpqi/smartpqi_response.c +++ b/sys/dev/smartpqi/smartpqi_response.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2025 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2026 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -275,7 +275,7 @@ pqisrc_is_innocuous_error(pqisrc_softstate_t *softs, rcb_t *rcb, void *err_info) if (raid_err->data_out_result == PQI_RAID_DATA_IN_OUT_UNDERFLOW) return true; - /* We get these a alot: leave a tiny breadcrumb about the error, + /* We get these a lot: leave a tiny breadcrumb about the error, but don't do full spew about it */ if (raid_err->status == PQI_AIO_STATUS_CHECK_CONDITION) { diff --git a/sys/dev/smartpqi/smartpqi_sis.c b/sys/dev/smartpqi/smartpqi_sis.c index 82eb999ca4b8..99aa952eb149 100644 --- a/sys/dev/smartpqi/smartpqi_sis.c +++ b/sys/dev/smartpqi/smartpqi_sis.c @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2025 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2026 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -26,7 +26,7 @@ #include "smartpqi_includes.h" -/* Function for disabling msix interrupots */ +/* Function for disabling msix interrupts */ void sis_disable_msix(pqisrc_softstate_t *softs) { @@ -96,7 +96,7 @@ sis_disable_interrupt(pqisrc_softstate_t *softs) sis_disable_msix(softs); break; default: - DBG_ERR("Inerrupt mode none!\n"); + DBG_ERR("Interrupt mode none!\n"); break; } diff --git a/sys/dev/smartpqi/smartpqi_structures.h b/sys/dev/smartpqi/smartpqi_structures.h index 0c9ad375823d..ada6676ada8f 100644 --- a/sys/dev/smartpqi/smartpqi_structures.h +++ b/sys/dev/smartpqi/smartpqi_structures.h @@ -1,5 +1,5 @@ /*- - * Copyright 2016-2025 Microchip Technology, Inc. and/or its subsidiaries. + * Copyright 2016-2026 Microchip Technology, Inc. and/or its subsidiaries. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -1168,7 +1168,7 @@ typedef struct bmic_sense_feature_page_header { uint8_t page; uint8_t sub_page; uint16_t total_length; /** Total length of the page. - * The length is the same wheteher the request buffer is too short or not. + * The length is the same whether the request buffer is too short or not. * When printing out the page, only print the buffer length. */ } OS_ATTRIBUTE_PACKED bmic_sense_feature_page_header_t; diff --git a/sys/dev/sound/pcm/sound.c b/sys/dev/sound/pcm/sound.c index 305d663cd6ad..9eb2dffeb908 100644 --- a/sys/dev/sound/pcm/sound.c +++ b/sys/dev/sound/pcm/sound.c @@ -242,7 +242,6 @@ pcm_getdevinfo(device_t dev) unsigned int pcm_getbuffersize(device_t dev, unsigned int minbufsz, unsigned int deflt, unsigned int maxbufsz) { - struct snddev_info *d = device_get_softc(dev); int sz, x; sz = 0; @@ -264,8 +263,6 @@ pcm_getbuffersize(device_t dev, unsigned int minbufsz, unsigned int deflt, unsig sz = deflt; } - d->bufsz = sz; - return sz; } @@ -406,12 +403,6 @@ pcm_register(device_t dev, char *str) SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "rec", CTLFLAG_RD | CTLFLAG_MPSAFE, 0, "recording channels node"); - /* XXX: a user should be able to set this with a control tool, the - sysadmin then needs min+max sysctls for this */ - SYSCTL_ADD_UINT(device_get_sysctl_ctx(dev), - SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), - OID_AUTO, "buffersize", CTLFLAG_RD, &d->bufsz, 0, - "allocated buffer size"); SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev), SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO, "bitperfect", CTLTYPE_INT | CTLFLAG_RWTUN | CTLFLAG_MPSAFE, d, diff --git a/sys/dev/sound/pcm/sound.h b/sys/dev/sound/pcm/sound.h index de9af6bd5324..4795eb7585c5 100644 --- a/sys/dev/sound/pcm/sound.h +++ b/sys/dev/sound/pcm/sound.h @@ -204,7 +204,6 @@ struct snddev_info { } channels; unsigned playcount, reccount, pvchancount, rvchancount; unsigned flags; - unsigned int bufsz; void *devinfo; device_t dev; char status[SND_STATUSLEN]; diff --git a/sys/dev/sound/usb/uaudio.c b/sys/dev/sound/usb/uaudio.c index 65976ced8a75..f477eb768fde 100644 --- a/sys/dev/sound/usb/uaudio.c +++ b/sys/dev/sound/usb/uaudio.c @@ -713,6 +713,10 @@ static driver_t uaudio_driver = { .size = sizeof(struct uaudio_softc), }; +static const STRUCT_USB_HOST_ID uaudio_vendor_audio[] = { + { USB_VPI(USB_VENDOR_ROLAND, 0x0132, 0) }, /* UA-33 */ +}; + /* The following table is derived from Linux's quirks-table.h */ static const STRUCT_USB_HOST_ID uaudio_vendor_midi[] = { { USB_VPI(USB_VENDOR_YAMAHA, 0x1000, 0) }, /* UX256 */ @@ -868,6 +872,11 @@ uaudio_probe(device_t dev) /* lookup non-standard device(s) */ + if (usbd_lookup_id_by_uaa(uaudio_vendor_audio, + sizeof(uaudio_vendor_audio), uaa) == 0) { + return (BUS_PROBE_SPECIFIC); + } + if (usbd_lookup_id_by_uaa(uaudio_vendor_midi, sizeof(uaudio_vendor_midi), uaa) == 0) { return (BUS_PROBE_SPECIFIC); @@ -6258,4 +6267,5 @@ MODULE_DEPEND(snd_uaudio, sound, SOUND_MINVER, SOUND_PREFVER, SOUND_MAXVER); MODULE_DEPEND(snd_uaudio, hid, 1, 1, 1); MODULE_VERSION(snd_uaudio, 1); USB_PNP_HOST_INFO(uaudio_devs); +USB_PNP_HOST_INFO(uaudio_vendor_audio); USB_PNP_HOST_INFO(uaudio_vendor_midi); diff --git a/sys/dev/usb/net/if_smsc.c b/sys/dev/usb/net/if_smsc.c index 8e16b8609144..c3c21fd22472 100644 --- a/sys/dev/usb/net/if_smsc.c +++ b/sys/dev/usb/net/if_smsc.c @@ -1296,7 +1296,7 @@ smsc_phy_init(struct smsc_softc *sc) } while ((bmcr & BMCR_RESET) && ((ticks - start_ticks) < max_ticks)); if (((usb_ticks_t)(ticks - start_ticks)) >= max_ticks) { - smsc_err_printf(sc, "PHY reset timed-out"); + smsc_err_printf(sc, "PHY reset timed-out\n"); return (EIO); } diff --git a/sys/dev/usb/quirk/usb_quirk.c b/sys/dev/usb/quirk/usb_quirk.c index 303f76f37fb0..c1976a59acbe 100644 --- a/sys/dev/usb/quirk/usb_quirk.c +++ b/sys/dev/usb/quirk/usb_quirk.c @@ -565,6 +565,7 @@ static struct usb_quirk_entry usb_quirks[USB_DEV_QUIRKS_MAX] = { USB_QUIRK(CMEDIA, CM6206, UQ_AU_SET_SPDIF_CM6206), USB_QUIRK(PLOYTEC, SPL_CRIMSON_1, UQ_CFG_INDEX_1), USB_QUIRK(ROLAND, UA25EX_AD, UQ_AU_VENDOR_CLASS), + USB_QUIRK(ROLAND, UA33, UQ_AU_VENDOR_CLASS), /* DYMO LabelManager Pnp */ USB_QUIRK(DYMO, LABELMANAGERPNP, UQ_MSC_DYMO_EJECT), diff --git a/sys/dev/usb/usbdevs b/sys/dev/usb/usbdevs index e1394e903cb3..594afafbb07f 100644 --- a/sys/dev/usb/usbdevs +++ b/sys/dev/usb/usbdevs @@ -4208,6 +4208,7 @@ product ROLAND UA700 0x002b UA-700 Audio I/F product ROLAND PCR300 0x0033 EDIROL PCR-300 MIDI I/F product ROLAND UA25EX_AD 0x00e6 EDIROL UA-25EX (Advanced Driver) product ROLAND UA25EX_CC 0x00e7 EDIROL UA-25EX (Class Compliant) +product ROLAND UA33 0x0132 UA-33 Audio I/F /* Rockfire products */ product ROCKFIRE GAMEPAD 0x2033 gamepad 203USB diff --git a/sys/dev/virtio/network/if_vtnet.c b/sys/dev/virtio/network/if_vtnet.c index 40792482672c..ef01833b9e03 100644 --- a/sys/dev/virtio/network/if_vtnet.c +++ b/sys/dev/virtio/network/if_vtnet.c @@ -96,17 +96,6 @@ #define VTNET_ETHER_ALIGN ETHER_ALIGN #endif -/* - * Worst case offset to ensure header doesn't share any cache lines with - * payload. - */ -#define VTNET_RX_BUFFER_HEADER_OFFSET 128 - -struct vtnet_rx_buffer_header { - bus_addr_t addr; - bus_dmamap_t dmap; -}; - static int vtnet_modevent(module_t, int, void *); static int vtnet_probe(device_t); @@ -219,7 +208,7 @@ static void vtnet_init_locked(struct vtnet_softc *, int); static void vtnet_init(void *); static void vtnet_free_ctrl_vq(struct vtnet_softc *); -static int vtnet_exec_ctrl_cmd(struct vtnet_softc *, uint8_t *, +static void vtnet_exec_ctrl_cmd(struct vtnet_softc *, void *, struct sglist *, int, int); static int vtnet_ctrl_mac_cmd(struct vtnet_softc *, uint8_t *); static int vtnet_ctrl_guest_offloads(struct vtnet_softc *, uint64_t); @@ -395,17 +384,6 @@ MODULE_DEPEND(vtnet, netmap, 1, 1, 1); VIRTIO_SIMPLE_PNPINFO(vtnet, VIRTIO_ID_NETWORK, "VirtIO Networking Adapter"); -static struct vtnet_rx_buffer_header * -vtnet_mbuf_to_rx_buffer_header(struct vtnet_softc *sc, struct mbuf *m) -{ - if (VTNET_ETHER_ALIGN != 0 && sc->vtnet_hdr_size % 4 == 0) - return (struct vtnet_rx_buffer_header *)((uintptr_t)m->m_data - - VTNET_RX_BUFFER_HEADER_OFFSET - VTNET_ETHER_ALIGN); - else - return (struct vtnet_rx_buffer_header *)((uintptr_t)m->m_data - - VTNET_RX_BUFFER_HEADER_OFFSET); -} - static int vtnet_modevent(module_t mod __unused, int type, void *unused __unused) { @@ -479,106 +457,6 @@ vtnet_attach(device_t dev) goto fail; } - mtx_init(&sc->vtnet_rx_mtx, device_get_nameunit(dev), - "VirtIO Net RX lock", MTX_DEF); - - error = bus_dma_tag_create( - bus_get_dma_tag(dev), /* parent */ - sizeof(uint16_t), /* alignment */ - 0, /* boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - MJUM9BYTES, /* max request size */ - 1, /* max # segments */ - MJUM9BYTES, /* maxsegsize - worst case */ - BUS_DMA_COHERENT, /* flags */ - busdma_lock_mutex, /* lockfunc */ - &sc->vtnet_rx_mtx, /* lockarg */ - &sc->vtnet_rx_dmat); - if (error) { - device_printf(dev, "cannot create bus_dma_tag\n"); - goto fail; - } - - mtx_init(&sc->vtnet_tx_mtx, device_get_nameunit(dev), - "VirtIO Net TX lock", MTX_DEF); - - error = bus_dma_tag_create( - bus_get_dma_tag(dev), /* parent */ - sizeof(uint16_t), /* alignment */ - 0, /* boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - sc->vtnet_tx_nsegs * MJUM9BYTES, /* max request size */ - sc->vtnet_tx_nsegs, /* max # segments */ - MJUM9BYTES, /* maxsegsize */ - BUS_DMA_COHERENT, /* flags */ - busdma_lock_mutex, /* lockfunc */ - &sc->vtnet_tx_mtx, /* lockarg */ - &sc->vtnet_tx_dmat); - if (error) { - device_printf(dev, "cannot create bus_dma_tag\n"); - goto fail; - } - - mtx_init(&sc->vtnet_hdr_mtx, device_get_nameunit(dev), - "VirtIO Net header lock", MTX_DEF); - - error = bus_dma_tag_create( - bus_get_dma_tag(dev), /* parent */ - sizeof(uint16_t), /* alignment */ - 0, /* boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - PAGE_SIZE, /* max request size */ - 1, /* max # segments */ - PAGE_SIZE, /* maxsegsize */ - BUS_DMA_COHERENT, /* flags */ - busdma_lock_mutex, /* lockfunc */ - &sc->vtnet_hdr_mtx, /* lockarg */ - &sc->vtnet_hdr_dmat); - if (error) { - device_printf(dev, "cannot create bus_dma_tag\n"); - goto fail; - } - - mtx_init(&sc->vtnet_ack_mtx, device_get_nameunit(dev), - "VirtIO Net ACK lock", MTX_DEF); - - error = bus_dma_tag_create( - bus_get_dma_tag(dev), /* parent */ - sizeof(uint8_t), /* alignment */ - 0, /* boundary */ - BUS_SPACE_MAXADDR, /* lowaddr */ - BUS_SPACE_MAXADDR, /* highaddr */ - NULL, NULL, /* filter, filterarg */ - sizeof(uint8_t), /* max request size */ - 1, /* max # segments */ - sizeof(uint8_t), /* maxsegsize */ - BUS_DMA_COHERENT, /* flags */ - busdma_lock_mutex, /* lockfunc */ - &sc->vtnet_ack_mtx, /* lockarg */ - &sc->vtnet_ack_dmat); - if (error) { - device_printf(dev, "cannot create bus_dma_tag\n"); - goto fail; - } - -#ifdef __powerpc__ - /* - * Virtio uses physical addresses rather than bus addresses, so we - * need to ask busdma to skip the iommu physical->bus mapping. At - * present, this is only a thing on the powerpc architectures. - */ - bus_dma_tag_set_iommu(sc->vtnet_rx_dmat, NULL, NULL); - bus_dma_tag_set_iommu(sc->vtnet_tx_dmat, NULL, NULL); - bus_dma_tag_set_iommu(sc->vtnet_hdr_dmat, NULL, NULL); - bus_dma_tag_set_iommu(sc->vtnet_ack_dmat, NULL, NULL); -#endif - error = vtnet_alloc_rx_filters(sc); if (error) { device_printf(dev, "cannot allocate Rx filters\n"); @@ -1667,11 +1545,6 @@ static struct mbuf * vtnet_rx_alloc_buf(struct vtnet_softc *sc, int nbufs, struct mbuf **m_tailp) { struct mbuf *m_head, *m_tail, *m; - struct vtnet_rx_buffer_header *vthdr; - bus_dma_segment_t segs[1]; - bus_dmamap_t dmap; - int nsegs; - int err; int i, size; m_head = NULL; @@ -1689,43 +1562,13 @@ vtnet_rx_alloc_buf(struct vtnet_softc *sc, int nbufs, struct mbuf **m_tailp) } m->m_len = size; - vthdr = (struct vtnet_rx_buffer_header *)m->m_data; - - /* Reserve space for header */ - m_adj(m, VTNET_RX_BUFFER_HEADER_OFFSET); - /* * Need to offset the mbuf if the header we're going to add * will misalign. */ - if (VTNET_ETHER_ALIGN != 0 && sc->vtnet_hdr_size % 4 == 0) + if (VTNET_ETHER_ALIGN != 0 && sc->vtnet_hdr_size % 4 == 0) { m_adj(m, VTNET_ETHER_ALIGN); - - err = bus_dmamap_create(sc->vtnet_rx_dmat, 0, &dmap); - if (err) { - printf("Failed to create dmamap, err :%d\n", - err); - m_freem(m); - return (NULL); - } - - nsegs = 0; - err = bus_dmamap_load_mbuf_sg(sc->vtnet_rx_dmat, dmap, m, segs, - &nsegs, BUS_DMA_NOWAIT); - if (err != 0) { - printf("Failed to map mbuf into DMA visible memory, err: %d\n", - err); - m_freem(m); - bus_dmamap_destroy(sc->vtnet_rx_dmat, dmap); - return (NULL); } - KASSERT(nsegs == 1, - ("%s: unexpected number of DMA segments for rx buffer: %d", - __func__, nsegs)); - - vthdr->addr = segs[0].ds_addr; - vthdr->dmap = dmap; - if (m_head != NULL) { m_tail->m_next = m; m_tail = m; @@ -1751,7 +1594,7 @@ vtnet_rxq_replace_lro_nomrg_buf(struct vtnet_rxq *rxq, struct mbuf *m0, int len, clustersz, nreplace, error; sc = rxq->vtnrx_sc; - clustersz = sc->vtnet_rx_clustersz - VTNET_RX_BUFFER_HEADER_OFFSET; + clustersz = sc->vtnet_rx_clustersz; /* * Need to offset the mbuf if the header we're going to add will * misalign, account for that here. @@ -1866,12 +1709,9 @@ vtnet_rxq_replace_buf(struct vtnet_rxq *rxq, struct mbuf *m, int len) static int vtnet_rxq_enqueue_buf(struct vtnet_rxq *rxq, struct mbuf *m) { - struct vtnet_rx_buffer_header *hdr; struct vtnet_softc *sc; struct sglist *sg; int header_inlined, error; - bus_addr_t paddr; - struct mbuf *mp; sc = rxq->vtnrx_sc; sg = rxq->vtnrx_sg; @@ -1884,38 +1724,28 @@ vtnet_rxq_enqueue_buf(struct vtnet_rxq *rxq, struct mbuf *m) header_inlined = vtnet_modern(sc) || (sc->vtnet_flags & VTNET_FLAG_MRG_RXBUFS) != 0; /* TODO: ANY_LAYOUT */ - hdr = vtnet_mbuf_to_rx_buffer_header(sc, m); - paddr = hdr->addr; - /* * Note: The mbuf has been already adjusted when we allocate it if we * have to do strict alignment. */ - if (header_inlined) { - error = sglist_append_phys(sg, paddr, m->m_len); - } else { + if (header_inlined) + error = sglist_append_mbuf(sg, m); + else { + struct vtnet_rx_header *rxhdr = + mtod(m, struct vtnet_rx_header *); MPASS(sc->vtnet_hdr_size == sizeof(struct virtio_net_hdr)); /* Append the header and remaining mbuf data. */ - error = sglist_append_phys(sg, paddr, sc->vtnet_hdr_size); + error = sglist_append(sg, &rxhdr->vrh_hdr, sc->vtnet_hdr_size); if (error) return (error); - error = sglist_append_phys(sg, - paddr + sizeof(struct vtnet_rx_header), + error = sglist_append(sg, &rxhdr[1], m->m_len - sizeof(struct vtnet_rx_header)); if (error) return (error); - mp = m->m_next; - while (mp) { - hdr = vtnet_mbuf_to_rx_buffer_header(sc, mp); - paddr = hdr->addr; - error = sglist_append_phys(sg, paddr, mp->m_len); - if (error) - return (error); - - mp = mp->m_next; - } + if (m->m_next != NULL) + error = sglist_append_mbuf(sg, m->m_next); } if (error) @@ -2101,7 +1931,6 @@ vtnet_rxq_merged_eof(struct vtnet_rxq *rxq, struct mbuf *m_head, int nbufs) m_tail = m_head; while (--nbufs > 0) { - struct vtnet_rx_buffer_header *vthdr; struct mbuf *m; uint32_t len; @@ -2111,10 +1940,6 @@ vtnet_rxq_merged_eof(struct vtnet_rxq *rxq, struct mbuf *m_head, int nbufs) goto fail; } - vthdr = vtnet_mbuf_to_rx_buffer_header(sc, m); - bus_dmamap_sync(sc->vtnet_rx_dmat, vthdr->dmap, - BUS_DMASYNC_POSTREAD); - if (vtnet_rxq_new_buf(rxq) != 0) { rxq->vtnrx_stats.vrxs_iqdrops++; vtnet_rxq_discard_buf(rxq, m); @@ -2235,7 +2060,6 @@ static int vtnet_rxq_eof(struct vtnet_rxq *rxq) { struct virtio_net_hdr lhdr, *hdr; - struct vtnet_rx_buffer_header *vthdr; struct vtnet_softc *sc; if_t ifp; struct virtqueue *vq; @@ -2251,31 +2075,14 @@ vtnet_rxq_eof(struct vtnet_rxq *rxq) CURVNET_SET(if_getvnet(ifp)); while (count-- > 0) { - struct mbuf *m, *mp; + struct mbuf *m; uint32_t len, nbufs, adjsz; - uint32_t synced; m = virtqueue_dequeue(vq, &len); if (m == NULL) break; deq++; - mp = m; - - /* - * Sync all mbufs in this packet. There will only be a single - * mbuf unless LRO is in use. - */ - synced = 0; - while (mp && synced < len) { - vthdr = vtnet_mbuf_to_rx_buffer_header(sc, mp); - bus_dmamap_sync(sc->vtnet_rx_dmat, vthdr->dmap, - BUS_DMASYNC_POSTREAD); - - synced += mp->m_len; - mp = mp->m_next; - } - if (len < sc->vtnet_hdr_size + ETHER_HDR_LEN) { rxq->vtnrx_stats.vrxs_ierrors++; vtnet_rxq_discard_buf(rxq, m); @@ -2535,14 +2342,6 @@ vtnet_txq_free_mbufs(struct vtnet_txq *txq) while ((txhdr = virtqueue_drain(vq, &last)) != NULL) { if (kring == NULL) { - bus_dmamap_unload(txq->vtntx_sc->vtnet_tx_dmat, - txhdr->dmap); - bus_dmamap_destroy(txq->vtntx_sc->vtnet_tx_dmat, - txhdr->dmap); - bus_dmamap_unload(txq->vtntx_sc->vtnet_tx_dmat, - txhdr->hdr_dmap); - bus_dmamap_destroy(txq->vtntx_sc->vtnet_tx_dmat, - txhdr->hdr_dmap); m_freem(txhdr->vth_mbuf); uma_zfree(vtnet_tx_header_zone, txhdr); } @@ -2712,36 +2511,15 @@ drop: return (NULL); } -static void -vtnet_txq_enqueue_callback(void *arg, bus_dma_segment_t *segs, - int nsegs, int error) -{ - vm_paddr_t *hdr_paddr; - - if (error != 0) - return; - - KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); - - hdr_paddr = (vm_paddr_t *)arg; - *hdr_paddr = segs[0].ds_addr; -} - static int vtnet_txq_enqueue_buf(struct vtnet_txq *txq, struct mbuf **m_head, struct vtnet_tx_header *txhdr) { - bus_dma_segment_t segs[VTNET_TX_SEGS_MAX]; - int nsegs; struct vtnet_softc *sc; struct virtqueue *vq; struct sglist *sg; struct mbuf *m; int error; - vm_paddr_t hdr_paddr; - bus_dmamap_t hdr_dmap; - bus_dmamap_t dmap; - int i; sc = txq->vtntx_sc; vq = txq->vtntx_vq; @@ -2749,55 +2527,15 @@ vtnet_txq_enqueue_buf(struct vtnet_txq *txq, struct mbuf **m_head, m = *m_head; sglist_reset(sg); - - error = bus_dmamap_create(sc->vtnet_tx_dmat, 0, &hdr_dmap); - if (error) - goto fail; - - error = bus_dmamap_load(sc->vtnet_tx_dmat, hdr_dmap, &txhdr->vth_uhdr, - sc->vtnet_hdr_size, vtnet_txq_enqueue_callback, &hdr_paddr, - BUS_DMA_NOWAIT); - if (error) - goto fail_hdr_dmamap_destroy; - - error = sglist_append_phys(sg, hdr_paddr, sc->vtnet_hdr_size); + error = sglist_append(sg, &txhdr->vth_uhdr, sc->vtnet_hdr_size); if (error != 0 || sg->sg_nseg != 1) { KASSERT(0, ("%s: cannot add header to sglist error %d nseg %d", __func__, error, sg->sg_nseg)); - goto fail_hdr_dmamap_unload; + goto fail; } - bus_dmamap_sync(sc->vtnet_tx_dmat, hdr_dmap, BUS_DMASYNC_PREWRITE); - - error = bus_dmamap_create(sc->vtnet_tx_dmat, 0, &dmap); - if (error) - goto fail_hdr_dmamap_unload; - - nsegs = 0; - error = bus_dmamap_load_mbuf_sg(sc->vtnet_tx_dmat, dmap, m, segs, - &nsegs, BUS_DMA_NOWAIT); - if (error != 0) - goto fail_dmamap_destroy; - KASSERT(nsegs <= sc->vtnet_tx_nsegs, - ("%s: unexpected number of DMA segments for tx buffer: %d (max %d)", - __func__, nsegs, sc->vtnet_tx_nsegs)); - - bus_dmamap_sync(sc->vtnet_tx_dmat, dmap, BUS_DMASYNC_PREWRITE); - - for (i = 0; i < nsegs && !error; i++) - error = sglist_append_phys(sg, segs[i].ds_addr, segs[i].ds_len); - + error = sglist_append_mbuf(sg, m); if (error) { - sglist_reset(sg); - bus_dmamap_unload(sc->vtnet_tx_dmat, dmap); - - error = sglist_append_phys(sg, hdr_paddr, sc->vtnet_hdr_size); - if (error != 0 || sg->sg_nseg != 1) { - KASSERT(0, ("%s: cannot add header to sglist error %d nseg %d", - __func__, error, sg->sg_nseg)); - goto fail_dmamap_destroy; - } - m = m_defrag(m, M_NOWAIT); if (m == NULL) { sc->vtnet_stats.tx_defrag_failed++; @@ -2807,41 +2545,16 @@ vtnet_txq_enqueue_buf(struct vtnet_txq *txq, struct mbuf **m_head, *m_head = m; sc->vtnet_stats.tx_defragged++; - nsegs = 0; - error = bus_dmamap_load_mbuf_sg(sc->vtnet_tx_dmat, dmap, m, - segs, &nsegs, BUS_DMA_NOWAIT); - if (error != 0) - goto fail_dmamap_destroy; - KASSERT(nsegs <= sc->vtnet_tx_nsegs, - ("%s: unexpected number of DMA segments for tx buffer: %d (max %d)", - __func__, nsegs, sc->vtnet_tx_nsegs)); - - bus_dmamap_sync(sc->vtnet_tx_dmat, dmap, BUS_DMASYNC_PREWRITE); - - for (i = 0; i < nsegs && !error; i++) - error = sglist_append_phys(sg, segs[i].ds_addr, - segs[i].ds_len); - + error = sglist_append_mbuf(sg, m); if (error) - goto fail_dmamap_unload; + goto fail; } txhdr->vth_mbuf = m; - txhdr->dmap = dmap; - txhdr->hdr_dmap = hdr_dmap; - error = virtqueue_enqueue(vq, txhdr, sg, sg->sg_nseg, 0); return (error); -fail_dmamap_unload: - bus_dmamap_unload(sc->vtnet_tx_dmat, dmap); -fail_dmamap_destroy: - bus_dmamap_destroy(sc->vtnet_tx_dmat, dmap); -fail_hdr_dmamap_unload: - bus_dmamap_unload(sc->vtnet_tx_dmat, hdr_dmap); -fail_hdr_dmamap_destroy: - bus_dmamap_destroy(sc->vtnet_tx_dmat, hdr_dmap); fail: m_freem(*m_head); *m_head = NULL; @@ -3797,43 +3510,10 @@ vtnet_free_ctrl_vq(struct vtnet_softc *sc) } static void -vtnet_load_callback(void *arg, bus_dma_segment_t *segs, int nsegs, - int error) -{ - bus_addr_t *paddr; - - if (error != 0) - return; - - KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs)); - - paddr = (bus_addr_t *)arg; - *paddr = segs[0].ds_addr; -} - -static int -vtnet_exec_ctrl_cmd(struct vtnet_softc *sc, uint8_t *ack, struct sglist *sg, - int readable, int writable) +vtnet_exec_ctrl_cmd(struct vtnet_softc *sc, void *cookie, + struct sglist *sg, int readable, int writable) { - bus_dmamap_t ack_dmap; - bus_addr_t ack_paddr; struct virtqueue *vq; - int error; - - error = bus_dmamap_create(sc->vtnet_ack_dmat, 0, &ack_dmap); - if (error) - goto error_out; - - error = bus_dmamap_load(sc->vtnet_ack_dmat, ack_dmap, ack, - sizeof(uint8_t), vtnet_load_callback, &ack_paddr, BUS_DMA_NOWAIT); - if (error) - goto error_destroy; - - bus_dmamap_sync(sc->vtnet_ack_dmat, ack_dmap, BUS_DMASYNC_PREWRITE); - - error = sglist_append_phys(sg, ack_paddr, sizeof(uint8_t)); - if (error) - goto error_unload; vq = sc->vtnet_ctrl_vq; @@ -3841,237 +3521,152 @@ vtnet_exec_ctrl_cmd(struct vtnet_softc *sc, uint8_t *ack, struct sglist *sg, VTNET_CORE_LOCK_ASSERT(sc); if (!virtqueue_empty(vq)) - goto error_unload; + return; /* * Poll for the response, but the command is likely completed before * returning from the notify. */ - if (virtqueue_enqueue(vq, (void *)ack, sg, readable, writable) == 0) { + if (virtqueue_enqueue(vq, cookie, sg, readable, writable) == 0) { virtqueue_notify(vq); virtqueue_poll(vq, NULL); } - - bus_dmamap_sync(sc->vtnet_ack_dmat, ack_dmap, BUS_DMASYNC_POSTREAD); - -error_unload: - bus_dmamap_unload(sc->vtnet_ack_dmat, ack_dmap); -error_destroy: - bus_dmamap_destroy(sc->vtnet_ack_dmat, ack_dmap); -error_out: - return (error); } static int vtnet_ctrl_mac_cmd(struct vtnet_softc *sc, uint8_t *hwaddr) { struct sglist_seg segs[3]; - bus_dmamap_t hdr_dmap; - bus_addr_t hdr_paddr; struct sglist sg; struct { struct virtio_net_ctrl_hdr hdr __aligned(2); uint8_t pad1; uint8_t addr[ETHER_ADDR_LEN] __aligned(8); uint8_t pad2; + uint8_t ack; } s; - uint8_t ack; int error; - error = bus_dmamap_create(sc->vtnet_hdr_dmat, 0, &hdr_dmap); - if (error) - goto error_out; - - error = bus_dmamap_load(sc->vtnet_hdr_dmat, hdr_dmap, &s, - sizeof(s), vtnet_load_callback, &hdr_paddr, BUS_DMA_NOWAIT); - if (error) - goto error_destroy_hdr; - + error = 0; MPASS(sc->vtnet_flags & VTNET_FLAG_CTRL_MAC); s.hdr.class = VIRTIO_NET_CTRL_MAC; s.hdr.cmd = VIRTIO_NET_CTRL_MAC_ADDR_SET; bcopy(hwaddr, &s.addr[0], ETHER_ADDR_LEN); - ack = VIRTIO_NET_ERR; - bus_dmamap_sync(sc->vtnet_hdr_dmat, hdr_dmap, BUS_DMASYNC_PREWRITE); + s.ack = VIRTIO_NET_ERR; sglist_init(&sg, nitems(segs), segs); - error |= sglist_append_phys(&sg, hdr_paddr, - sizeof(struct virtio_net_ctrl_hdr)); - error |= sglist_append_phys(&sg, - hdr_paddr + ((uintptr_t)&s.addr - (uintptr_t)&s), - ETHER_ADDR_LEN); - MPASS(error == 0 && sg.sg_nseg == nitems(segs) - 1); + error |= sglist_append(&sg, &s.hdr, sizeof(struct virtio_net_ctrl_hdr)); + error |= sglist_append(&sg, &s.addr[0], ETHER_ADDR_LEN); + error |= sglist_append(&sg, &s.ack, sizeof(uint8_t)); + MPASS(error == 0 && sg.sg_nseg == nitems(segs)); if (error == 0) - error = vtnet_exec_ctrl_cmd(sc, &ack, &sg, sg.sg_nseg, 1); - if (error == 0) - error = (ack == VIRTIO_NET_OK ? 0 : EIO); + vtnet_exec_ctrl_cmd(sc, &s.ack, &sg, sg.sg_nseg - 1, 1); - bus_dmamap_unload(sc->vtnet_hdr_dmat, hdr_dmap); -error_destroy_hdr: - bus_dmamap_destroy(sc->vtnet_hdr_dmat, hdr_dmap); -error_out: - return (error); + return (s.ack == VIRTIO_NET_OK ? 0 : EIO); } static int vtnet_ctrl_guest_offloads(struct vtnet_softc *sc, uint64_t offloads) { struct sglist_seg segs[3]; - bus_dmamap_t hdr_dmap; - bus_addr_t hdr_paddr; struct sglist sg; struct { struct virtio_net_ctrl_hdr hdr __aligned(2); uint8_t pad1; uint64_t offloads __aligned(8); uint8_t pad2; + uint8_t ack; } s; - uint8_t ack; int error; - error = bus_dmamap_create(sc->vtnet_hdr_dmat, 0, &hdr_dmap); - if (error) - goto error_out; - - error = bus_dmamap_load(sc->vtnet_hdr_dmat, hdr_dmap, &s, - sizeof(s), vtnet_load_callback, &hdr_paddr, BUS_DMA_NOWAIT); - if (error) - goto error_destroy_hdr; - + error = 0; MPASS(sc->vtnet_features & VIRTIO_NET_F_CTRL_GUEST_OFFLOADS); s.hdr.class = VIRTIO_NET_CTRL_GUEST_OFFLOADS; s.hdr.cmd = VIRTIO_NET_CTRL_GUEST_OFFLOADS_SET; s.offloads = vtnet_gtoh64(sc, offloads); - ack = VIRTIO_NET_ERR; - bus_dmamap_sync(sc->vtnet_hdr_dmat, hdr_dmap, BUS_DMASYNC_PREWRITE); + s.ack = VIRTIO_NET_ERR; sglist_init(&sg, nitems(segs), segs); - error |= sglist_append_phys(&sg, hdr_paddr, - sizeof(struct virtio_net_ctrl_hdr)); - error |= sglist_append_phys(&sg, - hdr_paddr + ((uintptr_t)&s.offloads - (uintptr_t)&s), - sizeof(uint64_t)); - MPASS(error == 0 && sg.sg_nseg == nitems(segs) - 1); + error |= sglist_append(&sg, &s.hdr, sizeof(struct virtio_net_ctrl_hdr)); + error |= sglist_append(&sg, &s.offloads, sizeof(uint64_t)); + error |= sglist_append(&sg, &s.ack, sizeof(uint8_t)); + MPASS(error == 0 && sg.sg_nseg == nitems(segs)); if (error == 0) - error = vtnet_exec_ctrl_cmd(sc, &ack, &sg, sg.sg_nseg, 1); - if (error == 0) - error = (ack == VIRTIO_NET_OK ? 0 : EIO); + vtnet_exec_ctrl_cmd(sc, &s.ack, &sg, sg.sg_nseg - 1, 1); - bus_dmamap_unload(sc->vtnet_hdr_dmat, hdr_dmap); -error_destroy_hdr: - bus_dmamap_destroy(sc->vtnet_hdr_dmat, hdr_dmap); -error_out: - return (error); + return (s.ack == VIRTIO_NET_OK ? 0 : EIO); } static int vtnet_ctrl_mq_cmd(struct vtnet_softc *sc, uint16_t npairs) { struct sglist_seg segs[3]; - bus_dmamap_t hdr_dmap; - bus_addr_t hdr_paddr; struct sglist sg; struct { struct virtio_net_ctrl_hdr hdr __aligned(2); uint8_t pad1; struct virtio_net_ctrl_mq mq __aligned(2); uint8_t pad2; + uint8_t ack; } s; - uint8_t ack; int error; - error = bus_dmamap_create(sc->vtnet_hdr_dmat, 0, &hdr_dmap); - if (error) - goto error_out; - - error = bus_dmamap_load(sc->vtnet_hdr_dmat, hdr_dmap, &s, - sizeof(s), vtnet_load_callback, &hdr_paddr, BUS_DMA_NOWAIT); - if (error) - goto error_destroy_hdr; - + error = 0; MPASS(sc->vtnet_flags & VTNET_FLAG_MQ); s.hdr.class = VIRTIO_NET_CTRL_MQ; s.hdr.cmd = VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET; s.mq.virtqueue_pairs = vtnet_gtoh16(sc, npairs); - ack = VIRTIO_NET_ERR; - bus_dmamap_sync(sc->vtnet_hdr_dmat, hdr_dmap, BUS_DMASYNC_PREWRITE); + s.ack = VIRTIO_NET_ERR; sglist_init(&sg, nitems(segs), segs); - error |= sglist_append_phys(&sg, hdr_paddr, - sizeof(struct virtio_net_ctrl_hdr)); - error |= sglist_append_phys(&sg, - hdr_paddr + ((uintptr_t)&s.mq - (uintptr_t)&s), - sizeof(struct virtio_net_ctrl_mq)); - MPASS(error == 0 && sg.sg_nseg == nitems(segs) - 1); + error |= sglist_append(&sg, &s.hdr, sizeof(struct virtio_net_ctrl_hdr)); + error |= sglist_append(&sg, &s.mq, sizeof(struct virtio_net_ctrl_mq)); + error |= sglist_append(&sg, &s.ack, sizeof(uint8_t)); + MPASS(error == 0 && sg.sg_nseg == nitems(segs)); if (error == 0) - error = vtnet_exec_ctrl_cmd(sc, &ack, &sg, sg.sg_nseg, 1); - if (error == 0) - error = (ack == VIRTIO_NET_OK ? 0 : EIO); + vtnet_exec_ctrl_cmd(sc, &s.ack, &sg, sg.sg_nseg - 1, 1); - bus_dmamap_unload(sc->vtnet_hdr_dmat, hdr_dmap); -error_destroy_hdr: - bus_dmamap_destroy(sc->vtnet_hdr_dmat, hdr_dmap); -error_out: - return (error); + return (s.ack == VIRTIO_NET_OK ? 0 : EIO); } static int vtnet_ctrl_rx_cmd(struct vtnet_softc *sc, uint8_t cmd, bool on) { struct sglist_seg segs[3]; - bus_dmamap_t hdr_dmap; - bus_addr_t hdr_paddr; struct sglist sg; struct { struct virtio_net_ctrl_hdr hdr __aligned(2); uint8_t pad1; uint8_t onoff; uint8_t pad2; + uint8_t ack; } s; - uint8_t ack; int error; - error = bus_dmamap_create(sc->vtnet_hdr_dmat, 0, &hdr_dmap); - if (error) - goto error_out; - - error = bus_dmamap_load(sc->vtnet_hdr_dmat, hdr_dmap, &s, - sizeof(s), vtnet_load_callback, &hdr_paddr, BUS_DMA_NOWAIT); - if (error) - goto error_destroy_hdr; - + error = 0; MPASS(sc->vtnet_flags & VTNET_FLAG_CTRL_RX); s.hdr.class = VIRTIO_NET_CTRL_RX; s.hdr.cmd = cmd; s.onoff = on; - ack = VIRTIO_NET_ERR; - bus_dmamap_sync(sc->vtnet_hdr_dmat, hdr_dmap, BUS_DMASYNC_PREWRITE); + s.ack = VIRTIO_NET_ERR; sglist_init(&sg, nitems(segs), segs); - error |= sglist_append_phys(&sg, hdr_paddr, - sizeof(struct virtio_net_ctrl_hdr)); - error |= sglist_append_phys(&sg, - hdr_paddr + ((uintptr_t)&s.onoff - (uintptr_t)&s), - sizeof(uint8_t)); - MPASS(error == 0 && sg.sg_nseg == nitems(segs) - 1); + error |= sglist_append(&sg, &s.hdr, sizeof(struct virtio_net_ctrl_hdr)); + error |= sglist_append(&sg, &s.onoff, sizeof(uint8_t)); + error |= sglist_append(&sg, &s.ack, sizeof(uint8_t)); + MPASS(error == 0 && sg.sg_nseg == nitems(segs)); if (error == 0) - error = vtnet_exec_ctrl_cmd(sc, &ack, &sg, sg.sg_nseg, 1); - if (error == 0) - error = (ack == VIRTIO_NET_OK ? 0 : EIO); + vtnet_exec_ctrl_cmd(sc, &s.ack, &sg, sg.sg_nseg - 1, 1); - bus_dmamap_unload(sc->vtnet_hdr_dmat, hdr_dmap); -error_destroy_hdr: - bus_dmamap_destroy(sc->vtnet_hdr_dmat, hdr_dmap); -error_out: - return (error); + return (s.ack == VIRTIO_NET_OK ? 0 : EIO); } static int @@ -4142,10 +3737,6 @@ vtnet_rx_filter_mac(struct vtnet_softc *sc) struct virtio_net_ctrl_hdr hdr __aligned(2); struct vtnet_mac_filter *filter; struct sglist_seg segs[4]; - bus_dmamap_t filter_dmap; - bus_addr_t filter_paddr; - bus_dmamap_t hdr_dmap; - bus_addr_t hdr_paddr; struct sglist sg; if_t ifp; bool promisc, allmulti; @@ -4185,25 +3776,6 @@ vtnet_rx_filter_mac(struct vtnet_softc *sc) if (promisc && allmulti) goto out; - error = bus_dmamap_create(sc->vtnet_hdr_dmat, 0, &hdr_dmap); - if (error) - goto out_error; - - error = bus_dmamap_load(sc->vtnet_hdr_dmat, hdr_dmap, &hdr, - sizeof(hdr), vtnet_load_callback, &hdr_paddr, BUS_DMA_NOWAIT); - if (error) - goto out_destroy_hdr; - - error = bus_dmamap_create(sc->vtnet_hdr_dmat, 0, &filter_dmap); - if (error) - goto out_unload_hdr; - - error = bus_dmamap_load(sc->vtnet_hdr_dmat, hdr_dmap, filter, - sizeof(*filter), vtnet_load_callback, &filter_paddr, - BUS_DMA_NOWAIT); - if (error) - goto out_destroy_filter; - filter->vmf_unicast.nentries = vtnet_gtoh32(sc, ucnt); filter->vmf_multicast.nentries = vtnet_gtoh32(sc, mcnt); @@ -4212,33 +3784,19 @@ vtnet_rx_filter_mac(struct vtnet_softc *sc) ack = VIRTIO_NET_ERR; sglist_init(&sg, nitems(segs), segs); - error |= sglist_append_phys(&sg, hdr_paddr, - sizeof(struct virtio_net_ctrl_hdr)); - error |= sglist_append_phys(&sg, - filter_paddr + ((uintptr_t)&filter->vmf_unicast - - (uintptr_t)filter), + error |= sglist_append(&sg, &hdr, sizeof(struct virtio_net_ctrl_hdr)); + error |= sglist_append(&sg, &filter->vmf_unicast, sizeof(uint32_t) + ucnt * ETHER_ADDR_LEN); - error |= sglist_append_phys(&sg, - filter_paddr + ((uintptr_t)&filter->vmf_multicast - - (uintptr_t)filter), + error |= sglist_append(&sg, &filter->vmf_multicast, sizeof(uint32_t) + mcnt * ETHER_ADDR_LEN); - MPASS(error == 0 && sg.sg_nseg == nitems(segs) - 1); + error |= sglist_append(&sg, &ack, sizeof(uint8_t)); + MPASS(error == 0 && sg.sg_nseg == nitems(segs)); if (error == 0) - error = vtnet_exec_ctrl_cmd(sc, &ack, &sg, sg.sg_nseg, 1); - if (error == 0) - error = (ack == VIRTIO_NET_OK ? 0 : EIO); - - bus_dmamap_unload(sc->vtnet_hdr_dmat, filter_dmap); -out_destroy_filter: - bus_dmamap_destroy(sc->vtnet_hdr_dmat, filter_dmap); -out_unload_hdr: - bus_dmamap_unload(sc->vtnet_hdr_dmat, hdr_dmap); -out_destroy_hdr: - bus_dmamap_destroy(sc->vtnet_hdr_dmat, hdr_dmap); -out_error: - if (error != 0) + vtnet_exec_ctrl_cmd(sc, &ack, &sg, sg.sg_nseg - 1, 1); + if (ack != VIRTIO_NET_OK) if_printf(ifp, "error setting host MAC filter table\n"); + out: if (promisc && vtnet_set_promisc(sc, true) != 0) if_printf(ifp, "cannot enable promiscuous mode\n"); @@ -4250,53 +3808,34 @@ static int vtnet_exec_vlan_filter(struct vtnet_softc *sc, int add, uint16_t tag) { struct sglist_seg segs[3]; - bus_dmamap_t hdr_dmap; - bus_addr_t hdr_paddr; struct sglist sg; struct { struct virtio_net_ctrl_hdr hdr __aligned(2); uint8_t pad1; uint16_t tag __aligned(2); uint8_t pad2; + uint8_t ack; } s; - uint8_t ack; int error; - error = bus_dmamap_create(sc->vtnet_hdr_dmat, 0, &hdr_dmap); - if (error) - goto error_out; - - error = bus_dmamap_load(sc->vtnet_hdr_dmat, hdr_dmap, &s, - sizeof(s), vtnet_load_callback, &hdr_paddr, BUS_DMA_NOWAIT); - if (error) - goto error_destroy_hdr; - + error = 0; MPASS(sc->vtnet_flags & VTNET_FLAG_VLAN_FILTER); s.hdr.class = VIRTIO_NET_CTRL_VLAN; s.hdr.cmd = add ? VIRTIO_NET_CTRL_VLAN_ADD : VIRTIO_NET_CTRL_VLAN_DEL; s.tag = vtnet_gtoh16(sc, tag); - ack = VIRTIO_NET_ERR; - bus_dmamap_sync(sc->vtnet_hdr_dmat, hdr_dmap, BUS_DMASYNC_PREWRITE); + s.ack = VIRTIO_NET_ERR; sglist_init(&sg, nitems(segs), segs); - error |= sglist_append_phys(&sg, hdr_paddr, - sizeof(struct virtio_net_ctrl_hdr)); - error |= sglist_append_phys(&sg, - hdr_paddr + ((uintptr_t)&s.tag - (uintptr_t)&s), - sizeof(uint16_t)); - MPASS(error == 0 && sg.sg_nseg == nitems(segs) - 1); + error |= sglist_append(&sg, &s.hdr, sizeof(struct virtio_net_ctrl_hdr)); + error |= sglist_append(&sg, &s.tag, sizeof(uint16_t)); + error |= sglist_append(&sg, &s.ack, sizeof(uint8_t)); + MPASS(error == 0 && sg.sg_nseg == nitems(segs)); if (error == 0) - error = vtnet_exec_ctrl_cmd(sc, &ack, &sg, sg.sg_nseg, 1); - if (error == 0) - error = (ack == VIRTIO_NET_OK ? 0 : EIO); + vtnet_exec_ctrl_cmd(sc, &s.ack, &sg, sg.sg_nseg - 1, 1); - bus_dmamap_unload(sc->vtnet_hdr_dmat, hdr_dmap); -error_destroy_hdr: - bus_dmamap_destroy(sc->vtnet_hdr_dmat, hdr_dmap); -error_out: - return (error); + return (s.ack == VIRTIO_NET_OK ? 0 : EIO); } static void diff --git a/sys/dev/virtio/network/if_vtnetvar.h b/sys/dev/virtio/network/if_vtnetvar.h index e445bdf6d6cb..eb5e6784b07f 100644 --- a/sys/dev/virtio/network/if_vtnetvar.h +++ b/sys/dev/virtio/network/if_vtnetvar.h @@ -190,18 +190,6 @@ struct vtnet_softc { struct mtx vtnet_mtx; char vtnet_mtx_name[16]; uint8_t vtnet_hwaddr[ETHER_ADDR_LEN]; - - bus_dma_tag_t vtnet_rx_dmat; - struct mtx vtnet_rx_mtx; - - bus_dma_tag_t vtnet_tx_dmat; - struct mtx vtnet_tx_mtx; - - bus_dma_tag_t vtnet_hdr_dmat; - struct mtx vtnet_hdr_mtx; - - bus_dma_tag_t vtnet_ack_dmat; - struct mtx vtnet_ack_mtx; }; /* vtnet flag descriptions for use with printf(9) %b identifier. */ #define VTNET_FLAGS_BITS \ @@ -285,10 +273,6 @@ struct vtnet_tx_header { } vth_uhdr; struct mbuf *vth_mbuf; - - bus_dmamap_t dmap; - - bus_dmamap_t hdr_dmap; }; /* diff --git a/sys/dev/virtio/p9fs/virtio_p9fs.c b/sys/dev/virtio/p9fs/virtio_p9fs.c index 2b276a60aa9a..19a32fea458e 100644 --- a/sys/dev/virtio/p9fs/virtio_p9fs.c +++ b/sys/dev/virtio/p9fs/virtio_p9fs.c @@ -464,16 +464,20 @@ static int vt9p_modevent(module_t mod, int type, void *unused) { int error; + static int loaded = 0; error = 0; switch (type) { case MOD_LOAD: - p9_init_zones(); - p9_register_trans(&vt9p_trans); + if (loaded++ == 0) { + p9_register_trans(&vt9p_trans); + } break; case MOD_UNLOAD: - p9_destroy_zones(); + if (--loaded == 0) { + p9_unregister_trans(&vt9p_trans); + } break; case MOD_SHUTDOWN: break; @@ -481,6 +485,7 @@ vt9p_modevent(module_t mod, int type, void *unused) error = EOPNOTSUPP; break; } + return (error); } diff --git a/sys/dev/vt/vt_core.c b/sys/dev/vt/vt_core.c index 68a9a71c3d72..f7cffcea5b92 100644 --- a/sys/dev/vt/vt_core.c +++ b/sys/dev/vt/vt_core.c @@ -1684,6 +1684,9 @@ vtterm_splash(struct vt_device *vd) uintptr_t image; vt_axis_t top, left; + if (KERNEL_PANICKED()) + return; + if ((vd->vd_flags & VDF_TEXTMODE) != 0 || (boothowto & RB_MUTE) == 0) return; |
